打卡信奥刷题(2074)用C++实现信奥 P11475 [COCI 2024/2025 #3] 红蓝牌 / Karte

P11475 [COCI 2024/2025 #3] 红蓝牌 / Karte

题目背景

译自 COCI 2024/2025 #3 T2。 1s,0.5G \texttt{1s,0.5G} 1s,0.5G。满分为 70 70 70

题目描述

在 Vito 的桌子上,有 N N N 张编号分别为 1 ∼ N 1\sim N 1N 的红牌和 M M M 张编号分别为 1 ∼ M 1\sim M 1M 的蓝牌。

将一张红牌和一张蓝牌称为「一对」,给定若干个二元组 ( c , p ) (c,p) (c,p)。若一对牌中,红牌编号为 c c c,蓝牌编号为 p p p,则称这对牌是好对

一个牌堆包含若干张红牌和若干张蓝牌。定义一个牌堆的价值 w w w 为牌堆中选出一对,使得这个对是一个好对的方案数。

r r r 为牌堆中红牌的数量, b b b 为牌堆中蓝牌的数量,定义牌堆的强度 s t r e n g t h \mathrm{strength} strength 为:

s t r e n g t h = w − X ⋅ r − Y ⋅ b \mathrm{strength}=w-X\cdot r-Y\cdot b strength=wXrYb

其中 X X X Y Y Y 是给定的常数。

帮助 Vito 确定:选择若干张红牌和蓝牌构成一个牌堆,这个牌堆的最大强度为多少。注意,他也可以一张牌都不选(即构成一个空的牌堆)。

输入格式

第一行,四个非负整数 N , M , X , Y N,M,X,Y N,M,X,Y

接下来 N N N 行,每行一个长度为 M M M 01 \texttt{01} 01 串,其中第 i i i 行的字符串中第 j j j 位为 1 1 1 表示 ( i , j ) (i,j) (i,j) 是好的,否则表示不是好的。

输出格式

输出一行一个非负整数,表示可以构成的牌堆的最大强度。

输入输出样例 #1

输入 #1

2 2 0 0
11
10

输出 #1

3

输入输出样例 #2

输入 #2

3 3 1 0
111
111
000

输出 #2

4

输入输出样例 #3

输入 #3

3 3 1 1
111
101
011

输出 #3

1

说明/提示

样例解释

样例 1 1 1 中,Vito 可以选择所有的卡牌,能产生 3 3 3 个好对,牌堆的最大强度为 3 3 3

样例 2 2 2 中,Vito 可以选择编号为 1 , 2 1,2 1,2 的红牌和所有的蓝牌,能产生 6 6 6 个好对,牌堆的最大强度为 4 4 4(由于选择了两张红牌,所以要将好对数减去 2 X = 2 2X=2 2X=2 作为牌堆的强度)。

数据范围

对于 100 % 100\% 100% 的数据,保证:

  • 1 ≤ N , M ≤ 21 1\le N,M\le 21 1N,M21
  • 0 ≤ X , Y ≤ 30 0\le X,Y\le 30 0X,Y30
  • 输入的字符串中仅包含 0 0 0 1 1 1
子任务编号特殊性质得分
1 1 1 Y = 0 Y=0 Y=0 18 18 18
2 2 2 1 ≤ N , M ≤ 9 1\le N,M\le 9 1N,M9 11 11 11
3 3 3 1 ≤ N , M ≤ 15 1\le N,M\le 15 1N,M15 24 24 24
4 4 4 17 17 17

C++实现

# include <bits/stdc++.h>
# define int LL
# define bpc __builtin_popcount
# define geti(x, i) (((x) >> (i)) & 1)
# define each1(i, x) for(auto (i) : (x))
# define each2(i, x) for(auto (&i) : (x))
# define rep(i, a, b) for(int i = (a); i <= (b); ++ i)
# define pre(i, a, b) for(int i = (a); i >= (b); -- i)
using namespace std;
using LL = long long;
const int N = 25;
int n, m, x, y, ans, val, cnt;
char ok[N][N];
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> n >> m >> x >> y;
	rep(i, 1, n){
		cin >> ok[i] + 1;
	}
	rep(s, 0, (1 << n) - 1){
		val = bpc(s) * (-x);
		rep(i, 1, m){
			cnt = 0;
			rep(j, 0, n - 1){
				if(geti(s, j)) cnt += (ok[j + 1][i] - '0'); 
			}
			if(cnt - y > 0) val += cnt - y;
		}
		ans = max(ans, val);
	}
	cout << ans;
	return 0;
}

在这里插入图片描述

后续

接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值