2021-11-12周赛总结

周赛总结

A:

Problem - 1334C - Codeforces

贪心题,xs,我一眼看上去就认定这题是dp,然后果断放弃,比赛结束问hls转移方程是什么,结果hls告诉我是贪心,呜呜呜(虽然感觉我也贪不出来)

题意:

一些怪兽,每个有两个属性:血量和死后的爆炸伤害,他们围成一个环,前一个死后爆炸会对后一个造成爆炸伤害(会连锁),问最少要手打多少血量才能全打死。

思路:

假设我第一个打爆了第i个怪兽,那么我下一次要去打爆的怪兽一定是第i+1个,因为无论如何我这第i+1个怪兽都是要被打爆的,我如果不现在打爆,那我就要手打掉第i+2个怪兽,但如果我现在打爆了第i+1个怪兽,第i+2个怪兽就会受到爆炸伤害,我手打的代价就小了,所以模拟这题的过程就是我选择一个打爆,然后一直打爆下一个,直到没有。这样就转化成了确定起点的问题,那我们该选谁作为起点呢?当然是选择我手打的代价和受到爆炸后再打的代价的差值最小的那一个,理由:模拟一下计算过程你会发现,除了第一个对答案的贡献是血量之外,其余所有的对答案的贡献都是血量-前一个的爆炸伤害,所以我们假设没有起点,那答案就是所有怪兽的血量-前一个爆炸伤害的总和,是个定值,那我现在有了一个起点,相当于把起点的血量-前一个爆炸伤害减掉,然后加上起点的血量,那不就是让这两个的差最小,增量就最小了吗。

 #include <bits/stdc++.h>
 using namespace std;
 #define ll long long
 struct node{
     ll a,b;
     ll mar;
 };
 node x[300001];
 int main(){
     //不关流同步会寄,我t了一次
     std::ios::sync_with_stdio(false);
     ll t;
     cin>>t;
     while(t--){
         ll n;
         cin>>n;
         for(ll i=0;i<n;i++){
             cin>>x[i].a>>x[i].b;
             if(i!=0){
                 x[i].mar=max(0LL,x[i].a-x[i-1].b);
             } 
         }
         ll ans=0;
         //long long 的话0x3f3f3f3f就不够了,再来几个,在这wa了一次
         ll ma=0x3f3f3f3f3f3f,maxindex=0;
         x[0].mar=max(0LL,x[0].a-x[n-1].b);
         for(ll i=0;i<n;i++){
             if(x[i].a-x[i].mar<ma){
                 ma=min(x[i].a-x[i].mar,ma);
                 maxindex=i;
             }
         }
         ans=x[maxindex].a;
         for(int i=0;i<n;i++){
             if(i==maxindex){
                 continue;
             }   
             ans+=x[i].mar;
         }
         cout<<ans<<endl;
     }   
     return 0;
 }

B:

Problem - 1372C - Codeforces

水题(,其实是我做过,但是我都忘了自己做过,感觉很眼熟,直接就a了。

题意:

给你一串数让你排序,你每次可以选择连续的一串,把它变为每一个都不在原来位置上的新串,问最少要几步能完成排序。

思路:

答案只有0,1,2,0不用说,原先就是有序的,1就是只有一串连续的数无序,且这串无序的数没有一个在它应该在的位置。2的情况就是我找不到1这种串,或者满足1的条件的串有多个,那我直接框框选中整个串变换两次即可,因为每个串的总情况是n的全排列,我第一次变换肯定能将其变为满足1的这种串,然后就变成1这种情况了。

可能算一个小技巧的操作就是我先把两端已经在自己位置上的数剔除,这样要处理的串就只有中间这一段了。

#include <bits/stdc++.h>
 using namespace std;
 #define ll long long 
 int x[200001];
 int main(){
     std::ios::sync_with_stdio(false);
     int t;
     cin>>t;
     while(t--){
         int n;
         cin>>n;
         for(int i=0;i<n;i++){
             cin>>x[i];
         }
         int flag=1;
         int i=0;
         int j=n-1;
         while(x[i]==i+1){
             i++;
         }
         while(x[j]==j+1){
             j--;
         }
         if(i>j){
             cout<<0<<endl;
             continue;
         }
         for(;i<=j;i++){
             if(x[i]==i+1){
                 flag=0;
                 break;
             }
         }
         if(flag==0){
             cout<<2<<endl;
         }else{
             cout<<1<<endl;
         }
     }   
     return 0;
 } 

C:

Problem - 1372D - Codeforces

哎呦,涵爹tql,拉了道2100的题,我看着挺简单,以为就是一个优先队列的模拟,结果人都傻了。

题意:

给你一个有奇数个数字的环,每次选择一个用相邻的两个的和代替,问最后得到的那个数的最大值是多少

思路:

如果我要使最后剩下的那个数最大,那我肯定要想办法让这个数由尽可能多的数拼成,模拟一下这个过程会发现,我最后剩下的这个数最多是由(n+1)/2个原来环里的数组成的,并且这(n+1)/2个数在原环中的排列一定是两两之间隔一个,并且有且仅有两个相邻的数(因为是个环)。那问题就变成如何在这些数中找出最大的满足上面的条件的数,但是你会发现如果直接找的话会很难找,原因就在它有一个可以相邻着取的数,那我们换一个角度思考,我每次隔一个取一个,那这些数的下标的奇偶性一定相同,当我选了一个相邻的数后,后面我再选的数的下标的奇偶性就全部相反,然后很妙的一个想法就来了,我想办法让我每次尺取的这个长度为(n+1)/2的子串只会并且一定会选到一对相邻的数,换句话说就是让每两个相邻的数的距离刚好是(n+1)/2-1,那再根据上面分析的奇偶性,我们可以构造一个这样的串:{a1,a3,a5....an,a2,a4,.....a(n-1)},这样尺取的时候就满足了上面的条件(妙蛙妙蛙,我直呼tql)。

 #include <bits/stdc++.h>
 using namespace std;
 #define ll long long
 int x[200001];
 int y[200001];
 int main(){
     int n;
     cin>>n;
     for(int i=1;i<=n;i++){
         cin>>x[i];
     }
     int i=1;
     for(;i<=n;i++){
         y[i]=x[2*i-1];
         if(2*i-1==n){
             break;
         }
     }
     for(int j=2;j<=n;j+=2){
         y[++i]=x[j];
     }
     ll now=0;
     i=1;
     int j=1;
     for(;j<=(n+1)/2;j++){
         now+=y[j]; 
     }
     ll ans=now;
     //尺取,也就是双指针,不会有人不会写尺取吧(bushi)
     for(;i<=n;i++){
         now=now-y[i]+y[j++];
         ans=max(ans,now);
         //小细节,j搜到头还没完,要i搜到头才行,因为是个环嘛,每个都可能为目标串的起点
         if(j==n+1){
             j=1;
         }
     }
     cout<<ans<<endl;
     return 0;
 }

D:

Problem - 1454C - Codeforces

签到题,不想写题解了,自己看吧,判重,遍历,特判两端就行了,但是还是有很多人被卡,不是很懂(虽然我wa了3次,艹,太fw了)。

 #include <bits/stdc++.h>
 using namespace std;
 #define ll long long 
 int x[200001];
 ​
 int num[200001];
 int main(){
     std::ios::sync_with_stdio(false);
     int t;
     cin>>t;
     while(t--){
         int n;  
         cin>>n;
         int nm=n;
         for(int i=0;i<=n;i++){
             num[i]=0;
         }
         for(int i=0;i<n;i++){
             cin>>x[i];
             if(i!=0&&x[i]==x[i-1]){
                 i--;
                 n--;
             }
         }
         if(n==1){
             cout<<0<<endl;
             continue;
         }
         for(int i=1;i<n-1;i++){
             if(num[x[i]]==0){
                 num[x[i]]++;
             }
             num[x[i]]++;
         }
         if(x[0]!=x[n-1]){
             if(num[x[0]]==0){
                 num[x[0]]++;
             }
             if(num[x[n-1]]==0){
                 num[x[n-1]]++;
             }
         }else{
             if(num[x[0]]==0){
                 num[x[0]]++;
             }           
         }   
         int ans=10000000;
         //我wa在这里,去重的时候n变小了,但是数据的范围还是原来的n的范围,相当于这里没遍历完,淦
         for(int i=1;i<=nm;i++){
             if(num[i]!=0){
                 ans=min(ans,num[i]);
             }
         }       
         if(ans==10000000){
             cout<<0<<endl;
             continue;
         }
         cout<<ans<<endl;    
     }
     return 0;
 } 

E:

Problem - 1421D - Codeforces

hls开了这题,我瞄了一眼,看了看题解,大概知道了啥意思,但是感觉码量不小,懒,不写了,

F:

Problem - 1451E2 - Codeforces

打开题面->看到位运算(心凉一半)->看到交互(果断放弃)->赛后补题->看到2300->果断下机,写作业去了。

Guess you like

Origin blog.csdn.net/m0_58178876/article/details/121300869