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 }

 

posted @ 2018-11-06 16:32  霜雪千年  阅读(1174)  评论(0编辑  收藏  举报