OB局,最近莽数据库作业没什么时间,大晚上也挺困的。
A - Tit for Tat
概括来讲,对于(n)个数,最多进行(k)次操作,每次操作可以使一个数-1,一个数+1,最终得到的序列字典序最小。
每次操作就对第一个非0的数-1,对最后一个数+1。
如果第一个非0的数就是最后一个数,就可以停止操作了。
/* Author: EndlessK * Time: 2021-04-22 12:37:38 **/ #include<bits/stdc++.h> #define maxn 100010 #define pb push_back #define ll long long #define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; int a[110]; int main() { fast; int t; cin>>t; while(t--) { int n,k; cin>>n>>k; for(int i=1;i<=n;i++) { cin>>a[i]; } int temp=1; for(int i=1;i<=k;i++) { while(a[temp]==0 && temp<n) temp++; if(temp==n) break; a[temp]--; a[n]++; } for(int i=1;i<=n;i++) { cout<<a[i]<<' '; } cout<<' '; } return 0; }
当时口糊一个算法,随便写了一发让别人交了,A了,第二天起来自己交Wrong answer on test 18,效果拉满。
题目概括起来讲就是将一个序列分成若干段,使得这几段的异或和相等。
两个相等的数异或和为0。
先求序列所有数字的异或和,如果为0,那么整个序列必然可以分成两段使得这两段的异或和相等。
如果不为0,那么留下的这个数字就是每段异或和的值(sum)。那么我就看前面异或和为0的部分能不能分成两段异或和为(sum)的序列。
当晚口糊的居然是看每一小段异或和为0的部分能不能分成两段异或和为(sum)的序列。早晨起来发现加了17和18两组,正好叉掉了。
1 #include <bits/stdc++.h> 2 #define maxn 100010 3 #define pb push_back 4 #define ll long long 5 #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) 6 const ll mod = 1e9 + 7; 7 using namespace std; 8 int n; 9 int a[2020]; 10 int sum[2020] = {0}; 11 vector<int> v; 12 bool check(int l, int r) 13 { 14 int temp = 0; 15 for (int i = l; i <= r; i++) 16 { 17 temp = temp ^ a[i]; 18 if (temp == sum[n]) 19 return 1; 20 } 21 return 0; 22 } 23 int main() 24 { 25 int t; 26 cin >> t; 27 while (t--) 28 { 29 v.clear(); 30 cin >> n; 31 for (int i = 1; i <= n; i++) 32 { 33 cin >> a[i]; 34 sum[i] = sum[i - 1] ^ a[i]; 35 if (sum[i] == 0) 36 v.pb(i); 37 } 38 if (sum[n] == 0) 39 cout << "YES "; 40 else 41 { 42 if (v.size() == 0) 43 { 44 cout << "NO "; 45 continue; 46 } 47 int flag = 1; 48 int tmp = 1; 49 if(check(1,v[v.size()-1])) cout<<"YES "; 50 else cout<<"NO "; 51 } 52 } 53 }
C - Baby Ehab Partitions Again
隔壁的暴力居然过了,虽然我到现在还在怀疑是不是对的。
概括起来就是,判断能不能将所有数字分成两组使得两组和相等,不能则为0,若能,问最少删除多少个数字使得无法分成符合条件的两组。
1.和为奇数,结果必为0。
2.和为偶数,若数字中有奇数,删除奇数。
3.对于上一条,若全为偶数,则不断除2,直至奇数出现,而那个奇数就是我们需要删除的数字。
对于所有可能和的求解像极了蓝桥的砝码称重()
终于想到用背包写了,谢天谢地,不然我还在那写set。
/* Author: EndlessK * Time: 2021-04-22 12:37:38 **/ #include<bits/stdc++.h> #define maxn 100010 #define pb push_back #define ll long long #define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; int a[120]; int sum=0; int main() { fast; int n; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; sum+=a[i]; } if(sum%2) { cout<<"0 "; return 0; } ll dp[sum/2+1][n+1]; memset(dp,0,sizeof(dp)); for(int i=0;i<=n;i++) { dp[0][i]=1; } for(int i=1;i<=sum/2;i++) { for(int j=1;j<=n;j++) { dp[i][j]=dp[i][j-1]; if(i>=a[j-1]) dp[i][j]=max(dp[i-a[j-1]][j-1],dp[i][j]); } } if(dp[sum/2][n]==0) { cout<<"0 "; return 0; } for(int i=1;i<=16;i++) { for(int j=1;j<=n;j++) { if(a[j]%2) { cout<<"1 "<<j<<' '; return 0; } else a[j]/=2; } } return 0; }
之后有空补一下剩下两道题。