Dividing Chocolate - AtCoder abc159_e - Virtual Judge
对于每一行来说我们可以直接暴力采用二进制枚举所有可能切割的情况,这里为什么会想到二进制呢,因为可以用二进制来表示每一行到底切还是不切,比如有四行,那么就用两位就可以表示所有情况:00,01,10,11四种切法,所以就可以通过位运算&1来判断当前这种情况下这一行切没切,从而实现判断这一列符合条件的时候也判断了行有没有切到位,如果切到位了,这一列肯定不会超,如果没切到位,那肯定就是行没有切到位,这时候再去切某一列就没有任何意义了,如果一行里超了的话那只能竖着切一刀,然后再判断一下如果竖着切了一刀后满不满足题意,如果还不行那就是行切少了,直接再判断下一种切行的情况而不更新答案
AC代码:#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair using namespace std; typedef long long ll; typedef pair<int,int>P; const double eps = 1e-8; const int NINF = 0xc0c0c0c0; const int INF = 0x3f3f3f3f; const ll mod = 1e9 + 7; const ll N = 1e3 + 5; int n,m,k,z; string s[15]; int c[15]; bool f(int j){//返回true代表要切一刀竖着的,因为至少有一块已经超过k了 int id=0; for(int i=0;i<n;i++){ c[id]+=s[i][j]=='1'; if(c[id]>k) return true;//超过k了 要切哦 if(z>>i & 1) id++; } return false;//不用切 依旧满足 } int main(){ ios::sync_with_stdio(false); cin.tie(0); cin>>n>>m>>k; for(int i=0;i<n;i++) cin>>s[i]; int ans=0x3f3f3f3f; for(z=0;z<1<<n-1;z++){//长度为n那么可以切n-1刀,枚举0~2^(n-1)-1的状态,1代表切,0代表不切。 memset(c,0,sizeof(c)); bool ok=false; int cnt=__builtin_popcount(z);//横着切了多少刀 for(int j=0;j<m;j++){//现在横着切完要贪心求竖着了 if(f(j)){//要竖着切一刀 cnt++;//竖着切了一刀 memset(c,0,sizeof(c));//那么切完之后竖着的每一块又都是0了 ok=f(j);//如果竖着切了一刀,哪怕是一列还是不行,那说明横着切少了,无论如何都不满足 } } if(!ok) ans=min(ans,cnt);//满足条件的时候记录最小值 } cout<<ans; return 0; }
Osenbei - Aizu 0525 - Virtual Judge
这个题说的是饼的反转,可以转行或者列,求最多能有多少1
AC代码:
#pragma GCC optimize(2) #pragma GCC optimize(3) //#pragma GCC optimize("Ofast") #include <iostream> #include <queue> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> #include <cstring> #include <string> #include <cctype> #include <map> #include <vector> #include <set> #include <stack> #include <numeric> #include <iomanip> #include <functional> using namespace std; #define lowbit(x) ((x) & -(x)) #define IOS1 ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); #define IOS2 ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); typedef vector<int> vi; typedef vector<long long> vll; typedef vector<char> vc; template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; } template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; } /* Tips: 1.int? long long? 2.don't submit wrong answer 3.figure out logic first, then start writing please 4.know about the range 5.check if you have to input t or not 6.modulo of negative numbers is not a%b, it is a%b + abs(b) */ const int INF = 0x3f3f3f3f; const int mod = 1000000007; int r, c; int ans; int a[20][10010]; void dfs(int x) { if (x == r + 1) { int sum = 0; for (int i = 1; i <= c; i++) { int c = 0; for (int j = 1; j <= r; j++) if (a[j][i] == 1)c++; sum += max(c, r - c); } ans = max(ans, sum); return; } dfs(x + 1); for (int i = 1; i <= c; i++) a[x][i] = !a[x][i]; dfs(x + 1); } void solve() { while (cin >> r >> c) { if (!r && !c) { return; } for (int i = 1; i <= r; i++) { for (int j = 1; j <= c; j++) { cin >> a[i][j]; } } ans = 0; dfs(1); cout << ans << endl; } } int main() { //IOS1; IOS2; int __t = 1; //cin >> __t; for (int _t = 1; _t <= __t; _t++) { solve(); } return 0; } /* */
这两个题都有一个特点就是行数特别少而列数特别多,因此可以枚举行来入手