题目链接
A题:Buy the String
题意:
给你一个长度为n的01串,你可以执行任意次翻转操作(即把第i位翻转),每次操作消耗的代价为h,定义0的代价为c0,1的代价为c1,对于一个串的代价就是0和1的代价和,求最小代价和。
题解:
我们考虑每一位,如果当前位为0,考虑翻转和不翻转的情况,那么最小的代价就是min(c0,c1+h),同理可以得出当前位为1的最小代价为min(c1,c0+h).最终的代价和就是所有为的最小代价的和。
代码:
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<long long,long long> #define pil pair<int,long long> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define debug puts("ac") #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f using namespace std; inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } inline long long lread(){ long long s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } const int N = 1e5+7; int main(){ int T=read(); while(T--){ int n=read(),c0=read(),c1=read(),h=read(); string s;cin>>s; int ans=0; rp(i,0,n-1){ if(c0>c1+h){ ans+=c1+(s[i]=='0')*h; } else if(c1>c0+h){ ans+=c0+(s[i]=='1')*h; } else{ if(s[i]=='0') ans+=c0; else ans+=c1; } } cout<<ans<<endl; } return 0; }
B题Sum of Medians
题意
给你n*k个数,需要把这些数分成k个大小为n的数列,保证这n个数列的中位数的和最大,并输出最大和。
题解
首先肯定需要排序,然后就考虑排序后怎么构造了,可以手推几个n试试能不能找到规律。
不难发现最终的开始位置是n*k-(n/2),长度是(n/2)+1,最终位置是((n-1)/2)*k+1.
答案就是这些位置的数字和(即中位数的和)。
代码
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define debug puts("ac") #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f using namespace std; inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } inline ll lread(){ ll s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } const int N = 1e6+7; int a[N]; int main(){ int T=read(); while(T--){ int n=read(),k=read(); rp(i,1,n*k) a[i]=read(); sort(a+1,a+1+n*k); ll sum=0; int cur=n*k-(n/2); while(cur>((n-1)/2)*k){ sum+=a[cur]; // cout<<cur<<" "<<endl; cur-=(n/2)+1; } cout<<sum<<endl; } return 0; }
C1题+C2题Binary Table (Easy Version)+Binary Table (Hard Version)
题意
给你一个n*m的01矩阵,你可以进行一种操作,即在一个2*2的矩阵中选三个位置,把这三个位置的数进行翻转。现在让你求出把这n*m的01矩阵变成全0矩阵的方案,简单版本需要保证最终答案的大小小于3*n*m,困难版本则是n*m.
题解
首先考虑简单版本的做法,我们考虑2*2的矩阵按照0和1的个数可以分成5种情况。
假设4个0为⑤,4个1为④,1个0和3个1为③,1个1和3个0为②,2个1和2个0是①。
他们之间的转换就是 ④->②->①->③->⑤。
虽然④状态转换到⑤状态需要4步,但是因为他是4个1,最终会把4个1都变成0,所以最终答案会保证在3*n*m内实现翻转为全0矩阵。
下面考虑困难版本的做法,这就需要比较巧妙的构造了,我们可以从最后一行开始,不断地把最后一行为1的位置变成0(即选择上一行和它相邻的两个位置和当前位置),最终会留下第一行和第二行,这里需要m*(n-2)步。
然后从右到左再把每一列都消成0,直至剩下前两列,即每次选择当前列为1的位置和上一列相邻的两个位置翻转,这里需要2*(m-2)步。
这时就只剩下前两行和前两列,有简单版本我们知道,一个2*2的矩阵消成全0矩阵最多需要4步,因此总步数为m*(n-2)+2*(m-2)+4=n*m。
最后的消除直接根据简单版本的做法暴力消就行了。
这个题码量还是不小的,不过参考了jiangly的做法,发现了一个码量不大的很妙的写法,下面给出代码。
代码
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define debug puts("ac") #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f using namespace std; inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } const int N = 1e6+7; char s[107][107]; int a[107][107]; vector<tuple<int,int,int,int,int,int>> res; int n,m; void change(int x1,int y1,int x2,int y2,int x3,int y3){ res.emplace_back(make_tuple(x1,y1,x2,y2,x3,y3)); a[x1][y1]^=1; a[x2][y2]^=1; a[x3][y3]^=1; } int main(){ int T=read(); while(T--){ res.clear(); int n=read(),m=read(); rp(i,0,n-1) scanf("%s",s[i]); rp(i,0,n-1) rp(j,0,m-1) a[i][j]=s[i][j]-'0'; RP(i,n-1,2){ rp(j,0,m-1){ if(a[i][j]==0) continue; if(j>0) change(i,j,i-1,j-1,i-1,j); else change(i,j,i-1,j+1,i-1,j); } } RP(i,m-1,2){ if(a[0][i]==1) change(0,i,0,i-1,1,i-1); if(a[1][i]==1) change(1,i,0,i-1,1,i-1); } if(a[1][1]==1) change(1,1,0,1,1,0); if(a[0][1]+a[1][0]+a[0][0]==3){ change(0,1,1,0,0,0); } else if(a[0][1]+a[1][0]==2){ change(0,0,1,1,0,1); change(0,0,1,1,1,0); } else if(a[0][1]+a[0][0]==2){ change(1,0,1,1,0,1); change(1,0,1,1,0,0); } else if(a[0][0]+a[1][0]==2){ change(0,1,1,1,0,0); change(0,1,1,1,1,0); } else if(a[0][0]==1){ change(0,0,1,0,1,1); change(0,0,0,1,1,0); change(0,0,0,1,1,1); } else if(a[0][1]==1){ change(0,1,0,0,1,1); change(0,1,1,0,0,0); change(0,1,1,0,1,1); } else if(a[1][0]==1){ change(1,0,0,0,1,1); change(1,0,0,1,0,0); change(1,0,0,1,1,1); } rp(i,0,n-1) rp(j,0,m-1) assert(a[i][j]==0); cout<<res.size()<<endl; for(auto tp:res) cout<<get<0>(tp)+1<<" "<<get<1>(tp)+1<<" "<<get<2>(tp)+1<<" "<<get<3>(tp)+1<<" "<<get<4>(tp)+1<<" "<<get<5>(tp)+1<<endl; } return 0; }