A. Buy the String
题目链接:A题
题目大意:
有一个01串,每个0的价格为c0,每个1的价格为c1,还可以花h元令串中某一个1变为0或0变为1,问买下这个01串最少要多少钱
分析:
签到题:
如果c0大于c1+h,就将所有的0变为1
如果c1大于c0+h,就将所有的1变为0
否则,不进行改变
代码:
#include <iostream>
#include <cstdio>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--){
int n,c0,c1,h;
cin>>n>>c0>>c1>>h;
string s;
cin>>s;
int n1=0,n2=0;
for(int i=0;i<s.size();i++){
if(s[i]=='0') n1++;
else n2++;
}
int ans;
if(c0>c1+h) ans=h*n1+s.size()*c1;
else if(c1>c0+h) ans=h*n2+s.size()*c0;
else ans=n1*c0+n2*c1;
printf("%d\n",ans);
}
return 0;
}
B. Sum of Medians
题目链接:B题
题目大意:
将median定义为一个长度为n的序列中[n/2](向上取整)的位置,现在给你一个长度为n*k的non-decreasing(非降)序列,让你将它拆成k个长度为n的序列,且要求这k个序列median位置上的元素值之和最大
分析:
贪心
将题目想象为从这个nk的序列中不断取出数字填充nk个格子:
假设n=4,k=3,则median=2
填充顺序应如下:
(序号表示在序列中的位置)
即:
①优先填充median位置前的格子
②然后填第一个序列的median位置
③填满第一个序列,这样能保证填下一个序列的median位置时数尽可能大
④填第二个序列的median位置
……
代码:
#include <iostream>
#include <cstdio>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--){
int n,k;
scanf("%d%d",&n,&k);
int median=(n+1)/2;
int pos=(median-1)*k+1;
int gap=n-median;
long long ans=0;
int t=0;
for(int i=1;i<=n*k;i++){
int temp;
scanf("%d",&temp);
if(i>=pos){
t++;
if(!gap||t%(gap+1)==1)
ans+=(long long)temp;
}
}
printf("%lld\n",ans);
}
return 0;
}
C. Binary Table (Easy Version and Hard Version)
题目链接:easy version,hard version
题目大意:
给你一个大小为n×m的01矩阵
翻转规则:
每一次翻转,在矩阵中取一个2×2的小矩阵,令这个矩阵中任意三个元素01翻转(由0变为1或由1变为0)
求一个翻转方式使整个矩阵变为0
easy version要求翻转次数在3nm以内
hard version要求翻转次数在nm以内
分析:
观察一个2*2的小矩阵:
有1个1时需要3次翻转
有2个1时需要2次翻转
有3个1时需要1次翻转
有4个1时需要4次翻转
题目给的nm次数暗示了每个元素处理一次
我的考虑方式:
**从第1行到第n-1行:**在每一行只考虑将当前行的1翻转为0。分块操作:两两一组,让当前行的第1个与第2个元素为1组,第3与第4个元素为一组……因为每次操作可以任意翻转3个元素,所以我们可以做到将每一组的1在一次操作内都变为0,剩下的元素就在下一行中随意翻转。
这样我们处理完前n-1行最多只需要
(
n
−
1
)
⋅
m
+
1
2
(n-1)\cdot\frac{m+1}{2}
(n−1)⋅2m+1次操作
对于最后一行元素:
从第一个元素枚举到m-2个元素
以该元素为左下角建立一个22矩阵
对于每次操作的3个元素,我们优先把最后一行的元素1变为0,剩下两个元素我们对22矩阵中的右边两个元素进行翻转,因为这样子的话枚举到下个元素时,可以把这两个元素处理为0
因此枚举到第i个元素时
我们只需要保证将第i个元素和上一行的第i个元素变为0,剩下的就交给枚举到第i+1个元素时来进行就可以了
也就是说只需要m-2次操作就可以处理完最后一行的前m-2个元素
剩下最后四个元素:
也就是原矩阵右下角的四个元素,对于一个2*2的矩阵我们可以保证在4次操作内将其翻转完
这个思路我并没有严格证明是否满足mn次操作,在m和n比较大的时候显然时满足的,因为对于前n-1行的分块操作比较高效,而在m和n较小时我也没找到反例,故姑且认为是没问题的吧
代码:
我写的非常长且冗余。。。
#include <iostream>
#include <cstdio>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;
typedef struct{
int x[3];
int y[3];
}operation;
int G[105][105];
operation op[30005];
int cnt=0;
int change(int x){
if(x==1) return 0;
else return 1;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
int n,m;
cnt=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
char temp;
scanf(" %c",&temp);
G[i][j]=temp-'0';
}
if(n*m>4)
for(int i=1;i<n;i++)
for(int j=1;j<m;j++){
int temp=0;
if(G[i][j]==0&&j!=m-1) continue;
if(G[i][j]==0&&j==m-1){
if(G[i][j+1]==0) continue;
op[cnt].x[temp]=i,op[cnt].y[temp++]=j+1,op[cnt].x[temp]=i+1,op[cnt].y[temp++]=j, op[cnt].x[temp]=i+1,op[cnt++].y[temp]=j+1;
G[i][j+1]=change(G[i][j+1]),G[i+1][j]=change(G[i+1][j]),G[i+1][j+1]=change(G[i+1][j+1]);
continue;
}
op[cnt].x[temp]=i,op[cnt].y[temp++]=j,op[cnt].x[temp]=i+1,op[cnt].y[temp++]=j;
G[i][j]=change(G[i][j]),G[i+1][j]=change(G[i+1][j]);
if(G[i][j+1]==1)
op[cnt].x[temp]=i,op[cnt++].y[temp]=j+1,G[i][j+1]=change(G[i][j+1]);
else
op[cnt].x[temp]=i+1,op[cnt++].y[temp]=j+1,G[i+1][j+1]=change(G[i+1][j+1]);
}
for(int i=1;i<m-1;i++){
int temp=0;
if(G[n][i]==0&&G[n-1][i]==0) continue;
if(G[n][i]==1) op[cnt].x[temp]=n,op[cnt].y[temp++]=i,G[n][i]=0;
if(G[n-1][i]==1) op[cnt].x[temp]=n-1,op[cnt].y[temp++]=i,G[n-1][i]=0;
op[cnt].x[temp]=n,op[cnt].y[temp++]=i+1;
G[n][i+1]=change(G[n][i+1]);
if(temp==2) op[cnt].x[temp]=n-1,op[cnt].y[temp++]=i+1,G[n-1][i+1]=change(G[n-1][i+1]);
cnt++;
}
int x[4]={n,n,n-1,n-1};
int y[4]={m,m-1,m,m-1};
int num=0;
for(int k=0;k<4;k++)
if(G[x[k]][y[k]]==1)
num++;
int temp=0;
if(num==3){
for(int k=0;k<4;k++)
if(G[x[k]][y[k]]==1)
op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
cnt++;
}
if(num==2){
int fx,fy;
for(int k=0;k<4;k++)
if(G[x[k]][y[k]]==1){
fx=x[k],fy=y[k];break;
}
for(int k=0;k<4;k++)
if(!(x[k]==fx&&y[k]==fy))
op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
cnt++;
temp=0;
for(int k=0;k<4;k++)
if(G[x[k]][y[k]]==1)
op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
cnt++;
}
if(num==1){
int fx,fy;
for(int k=0;k<4;k++)
if(G[x[k]][y[k]]==0){
fx=x[k],fy=y[k];break;
}
for(int k=0;k<4;k++)
if(!(x[k]==fx&&y[k]==fy))
op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
cnt++;
temp=0;
for(int k=0;k<4;k++)
if(G[x[k]][y[k]]==1){
fx=x[k],fy=y[k];break;
}
for(int k=0;k<4;k++)
if(!(x[k]==fx&&y[k]==fy))
op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
cnt++;
temp=0;
for(int k=0;k<4;k++)
if(G[x[k]][y[k]]==1)
op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
cnt++;
}
if(num==4){
for(int k=0;k<3;k++)
op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
cnt++;
temp=0;
int fx,fy;
for(int k=0;k<4;k++)
if(G[x[k]][y[k]]==0){
fx=x[k],fy=y[k];break;
}
for(int k=0;k<4;k++)
if(!(x[k]==fx&&y[k]==fy))
op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
cnt++;
temp=0;
for(int k=0;k<4;k++)
if(G[x[k]][y[k]]==1){
fx=x[k],fy=y[k];break;
}
for(int k=0;k<4;k++)
if(!(x[k]==fx&&y[k]==fy))
op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
cnt++;
temp=0;
for(int k=0;k<4;k++)
if(G[x[k]][y[k]]==1)
op[cnt].x[temp]=x[k],op[cnt].y[temp++]=y[k],G[x[k]][y[k]]=change(G[x[k]][y[k]]);
cnt++;
}
printf("%d\n",cnt);
for(int i=0;i<cnt;i++){
for(int k=0;k<3;k++)
k==0?printf("%d %d",op[i].x[k],op[i].y[k]):printf(" %d %d",op[i].x[k],op[i].y[k]);
printf("\n");
}
}
return 0;
}