2 条题解

  • 1
    @ 2026-8-7 9:50:38

    全部 1ms!!

    分享一种二分 + 贪心的高效做法喵。

    在 n,m 数据达到 2000 时也是可以通过的哦。

    点赞支持猫娘爆标喵。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 100;
    char s[N][N];
    int t[N];
    vector<int> G[N];
    // h:1, l:0
    
    int n, m, X, Y, a[N], b[N];
    int sum, mid;
    bool v[N];
    
    bool cmp(int na, int nb) {
    	return t[na] > t[nb];
    }
    
    bool check() {
    	sum = 0;
    	memset(v, 0, sizeof(v));
    	if (X > Y) {
    		for (int i = 1; i <= n; i ++) {
    			a[i] = i;
    		}
    		sort (a + 1, a + n + 1, cmp);
    		for (int i = 1; i <= n; i ++) {
    			int now = a[i];
    			
    			sum -= X;
    			sum += t[now];
    			for (int j : G[now]) if (!v[j]) {
    				v[j] = 1;
    				sum -= Y;
    			}
    			if (sum >= mid) {
    				return 1;
    			} 
    		}
    		return 0;
    	}
    	else {
    		for (int j = 1; j <= m; j ++) {
    			b[j] = j;
    		}
    		sort (b + 1, b + m + 1, cmp);
    		for (int i = 1; i <= m; i ++) {
    			int now = b[i];
    			
    			sum -= Y;
    			sum += t[now];
    			for (int j : G[now]) if (!v[j]) {
    				v[j] = 1;
    				sum -= X;
    			}
    			if (sum >= mid) {
    				return 1;
    			} 
    		}
    		return 0;
    	}
    }
    
    int main () {
    	ios::sync_with_stdio(false);
    	cin.tie(0);
    	
    	cin >> n >> m >> X >> Y;
    	memset(t, 0, sizeof(t));
    	
    	for (int i = 1; i <= n; i ++) {
    		cin >> (s[i] + 1);
    		for (int j = 1; j <= m; j ++) {
    			if (s[i][j] == '1') {
    				G[i].push_back(j + n);
    				G[j + n].push_back(i);
    				t[i] ++; t[j + n] ++;
    			}
    		}
    	}
    	
    	
    	
    	int l = 0, r = 450, ans = 0;
    	while (l <= r) {
    		mid = (l + r) / 2;
    		if (check()) {
    			l = mid + 1;
    			ans = mid;
    		}
    		else {
    			r = mid - 1;
    		}
    	}
    	cout << ans  << "\n";
    	
    	return 0;
    } 
    
    
    • 0
      @ 2026-8-5 10:18:32

      为啥我翻了一下其他大佬的题解,他们都没一个用递归来写啊,我来发一篇递归的!

      思路

      注意到本题数据范围极小考虑使用递归算法。我们可以递归枚举选择那些蓝牌,然后计算选择这些蓝牌可以构造出牌堆的最大强度(枚举每个红牌,看看选上这个红牌能不能增加牌堆的强度,能就把它选上)。

      代码

      带有详细注释代码:

      #include<bits/stdc++.h>
      using namespace std;
      int n,m,x,y,ans,f[22];
      bool ff[22][22],fff[22][22];
      char c;
      int js()
      {
      	int sum=0;
      	for(int i=1;i<=n;i++)
      	{
      		f[i]=0;
      		//清空,否则一分没有(别问我怎么知道的) 
      		for(int j=1;j<=m;j++)
      		{
      			f[i]+=fff[i][j];
      		}
      	}
      	//对于每张红牌,算出选它能和多少张蓝牌组成好对。 
      	for(int i=1;i<=n;i++)
      	{
      		sum+=max(0,f[i]-x);
      		//如果选这张红牌能贡献答案,就选上它,否则不选。 
      	}
      	return sum;
      }
      void dfs(int now,int w)
      //参数分别表示现在枚举的是第几张蓝牌,现在选上的蓝牌已经对答案产生了多少负的贡献 
      {
      	if(now==m+1)
      	{
      		ans=max(ans,js()-w);
      		return ;
      	}
      	//如果已经选完了,就计算并更新答案。 
      	for(int i=1;i<=n;i++)
      	{
      		fff[i][now]=ff[i][now];
      	}
      	//如果选了这张蓝牌,就把这张蓝牌所对应的所有红牌标记为可用(前提是它本身就能组成好对) 
      	dfs(now+1,w+y);
      	//继续递归 
      	for(int i=1;i<=n;i++)
      	{
      		fff[i][now]=0;
      	}
      	//回溯 
      	dfs(now+1,w);
      	//不选 
      }
      int main()
      {
      	cin>>n>>m>>x>>y;
      	for(int i=1;i<=n;i++)
      	{
      		for(int j=1;j<=m;j++)
      		{
      			cin>>c;
      			ff[i][j]=c-'0';
      		}
      	}
      	//读入数据 
      	dfs(1,0);
      	//递归 
      	cout<<ans;
      	//输出 
      	return 0;
      }
      
      • 1

      信息

      ID
      12546
      时间
      1000ms
      内存
      600MiB
      难度
      7
      标签
      递交数
      64
      已通过
      15
      上传者