2018 ACM-ICPC亚洲区域赛(青岛)
Problem C---zoj 4060 Flippy Sequence
解题思路:要求进行两次操作,每次操作选择一个区间,问将s串变成t串中所选的两个区间构成的4元组有多少个。做法:找出s串与t串不同块的个数,然后做个简单的判断即可。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int maxn=1e6+5; 5 int T,n,cnt,answer;char s1[maxn],s2[maxn]; 6 int main(){ 7 while(~scanf("%d",&T)){ 8 while(T--){ 9 scanf("%d %s %s",&n,s1,s2);cnt=0; 10 for(int i=0;i<n;++i)//统计s串与t串不同块的个数 11 if((i==0&&s1[i]!=s2[i])||(i>0&&s1[i-1]==s2[i-1]&&s1[i]!=s2[i]))cnt++; 12 if(!cnt)answer=n*(n+1)/2;//全部相同:1+...+n 13 else if(cnt==1)answer=2*(n-1);//只有一个不同块,①不同和不同进行反转,②不同和相同进行反转 14 else if(cnt==2)answer=6;//有两个不同块,三种操作,答案肯定为6 15 else answer=0;//至少有3个不同块,无法实现2次操作,答案只能为0 16 printf("%d\n",answer); 17 } 18 } 19 return 0; 20 }
Problem E---zoj 4062 Plants vs. Zombies
(补)解题思路:典型的最大化最小值,二分解法再加个贪心,详解看代码。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int maxn=1e5+5; 5 int T,n;LL m,l,r,mid,a[maxn],d[maxn]; 6 bool check(LL x){ 7 ///二分总防御值,对于固定的防御值x,显然花园里的每个植物都要不小于x,因此贪心地从左往右寻找每一个防御值小于x的植物,对它和它右侧的植物反复浇水。 8 LL step=0; 9 for(int i=0;i<n;++i)d[i]=x/a[i]+(x%a[i]?1LL:0LL);///计算每个至少需要浇水的次数 10 for(int i=0;i<n;++i){ 11 if(!d[i]){ 12 if(i!=n-1)step++;///如果最后一棵植物需要浇水的次数为0,说明其防御值不小于当前x,则无需计数 13 }else{ 14 step+=d[i]*2LL-1LL;///累加从i-1走到i这1步+浇完第i棵植物后花费的总步数为2*d[i]-1 15 d[i+1]-=(d[i]-1LL);///第i+1棵植物需要浇水的次数要减去(d[i]-1) 16 if(d[i+1]<0)d[i+1]=0LL;///如果d[i+1]<0,说明下一棵植物的防御值早已大于x,下次只需给它浇一次水(贪心向右移动一步)即可 17 } 18 if(step>m)return false;///如果所走步数超过m,则直接返回0,找较小的答案x 19 } 20 return true; 21 } 22 int main(){ 23 while(~scanf("%d",&T)){ 24 while(T--){ 25 scanf("%d%lld",&n,&m); 26 for(int i=0;i<n;++i)scanf("%lld",&a[i]); 27 l=1LL,r=1e18; 28 while(l<=r){///[l,r],退出条件是l>r,即l-1==r 29 mid=(l+r)>>1; 30 if(check(mid))l=mid+1LL;///还有满足条件的最小值,继续最大化 31 else r=mid-1LL;///不满足条件,往左找 32 ///cout<<l<<' '<<r<<endl; 33 } 34 printf("%lld\n",l-1);///l-1相当于r,因为l会不断被最大化,直到超过r,则可以取l-1或者r就是最大化最小值答案 35 } 36 } 37 return 0; 38 }
Problem J---zoj 4067 Books
解题思路:没有理解好题意,因此赛场上丧心病狂调了2小时的bug,罚时巨多QWQ,其实就是个简单的贪心=_=。题意:DreamGrid带的钱会在1~n本书中从前往后进行挑选,如果当前剩余的钱不小于第i本书的价格,那么他就一定会买这本书,并且用剩余的钱减去第i本书的价格,直到买完m本书,否则就跳过不买第i本书籍。首先要明确的一点:从其往后有序挑选!!!分三种情况:①当m==n时,显然为"Richman";②当m<cnt_0时,此时可以买比m多的书籍,显然为"Impossible";③当m>cnt_0时,首先肯定会挑选cnt_0个价格为0的书籍,然后从前往后在价格不为0的书籍里面贪心挑选(m-cnt_0)本书籍,再加上后面不为0的最小价格-1即为DreamGrid可带的最多零钱。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL;LL ans;//注意用long long 4 const int inf=0x3f3f3f3f; 5 const int maxn=1e5+5; 6 int T,n,m,cnt_0,pos,mina,s[maxn]; 7 int main(){ 8 while(cin>>T){ 9 while(T--){ 10 cin>>n>>m;cnt_0=0; 11 for(int i=0;i<n;++i)cin>>s[i],cnt_0+=s[i]?0:1;//统计0的个数 12 if(m==n)puts("Richman"); 13 else if(cnt_0>m)puts("Impossible");//如果0的个数大于m,肯定可以买更多的书籍,显然此时为不可能 14 else{ 15 m-=cnt_0,mina=inf,pos=0,ans=0;//m为剩下要挑选的本数 16 while(m)s[pos]?ans+=s[pos++],m--:pos++;//贪心选择价格不为0的m本,然后在后面选择一本最小的价格(不为0)-1加上来即为最优答案 17 for(int i=pos;i<n;++i)//从连续选择pos个不为0的数后,再从后面选择不为0的最小价格 18 if(s[i])mina=min(mina,s[i]); 19 cout<<(ans+=mina-1)<<endl; 20 } 21 } 22 } 23 return 0; 24 }
Problem M---zoj 4070 Function and Function
解题思路:签道题,注意:输入的x为0时要单独考虑。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 int T,x,k,s[]={1,0,0,0,1,0,1,0,2,1}; 5 int g(int y){ 6 int ans=0; 7 while(y){ans+=s[y%10];y/=10;} 8 return ans; 9 } 10 int main(){ 11 while(~scanf("%d",&T)){ 12 while(T--){ 13 scanf("%d%d",&x,&k); 14 if(!x)x=k&1?1:0;//x为0要单独考虑 15 else{ 16 for(int i=1;i<=k&&x;++i){ 17 x=g(x); 18 if(!x){x=(k-i)&1?1:0;break;} 19 } 20 } 21 printf("%d\n",x); 22 } 23 } 24 return 0; 25 }