Codeforces Round #579 (Div. 3) 套題 題解

A. Circle of Students     c++

題目:https://codeforces.com/contest/1203/problem/A數組

題意:一堆人坐成一個環,問可否按逆時針或者順時針正好是 1-n的順序ide

思路:水題,把數組開兩倍,或者標記當前位置均可以spa

#include<bits/stdc++.h>
#define maxn 100005
#define mod 1000000007
using namespace std; typedef long long ll; int a[maxn],n; int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); int dex=0; for(int i=1;i<=n;i++){ if(a[i]==1){ dex=i; break; } } int flag=0; int k=dex; int z=1,num=1; while(num<n){ k++; if(k==n+1) k=1; if(a[k]!=z+1) break; num++; z++; } if(num==n) flag=1; //printf("num=%d k=%d z=%d\n",num,k,z);
        k=dex; z=1,num=1; while(num<n){ k--; if(k==0) k=n; if(a[k]!=z+1) break; num++; z++; } if(num==n) flag=1; if(flag) printf("YES\n"); else printf("NO\n"); } }
View Code

 

B. Equal Rectangles指針

題目:https://codeforces.com/contest/1203/problem/Bcode

題意:有4*n根木棍,如今問可否組成n個面積相等的矩形blog

思路:首先咱們組成第一個矩形確定是最小和最大,而後第二個是次小和次大.....因此咱們對木棒排序,而後兩個指針判是否可行便可排序

#include<bits/stdc++.h>
#define maxn 100005
#define mod 1000000007
using namespace std; typedef long long ll; int a[maxn],n; int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d",&n); n=4*n; for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+n+1); int l=1,r=n,z=a[1]*a[n]; int flag=0; while(l<r){ if(a[l]!=a[l+1]||a[r]!=a[r-1]){ flag=1; break; } if(a[l]*a[r]!=z){ flag=1; break; } z=a[l]*a[r]; l+=2; r-=2; } if(flag) printf("NO\n"); else printf("YES\n"); } }
View Code

 

C. Common Divisorsci

題目:https://codeforces.com/contest/1203/problem/Cget

題意:有一個序列,如今求一個數x,這個x是序列全部數的約數,求這樣的x的數量

思路:咱們首先能求出最大公約數,而後其餘約數必然是最大公約數的因子,因此咱們求出最大公約數的因子數便可

#include<bits/stdc++.h>
#define maxn 400005
#define mod 1000000007
using namespace std; typedef long long ll; ll a[maxn],n; int main(){ scanf("%I64d",&n); for(ll i=1;i<=n;i++){ scanf("%I64d",&a[i]); } if(n==1){ ll sum=0; ll g=a[1]; for(ll i=1;i*i<=g;i++){ if(g%i==0){ sum++; if(i!=g/i) sum++; } } cout<<sum; return 0; } ll g=__gcd(a[1],a[2]); for(ll i=3;i<=n;i++){ g=__gcd(g,a[i]); } ll sum=0; for(ll i=1;i*i<=g;i++){ if(g%i==0){ sum++; if(i!=g/i) sum++; } } cout<<sum; return 0; }
View Code

 

D1+D2. Remove the Substring

題目:https://codeforces.com/contest/1203/problem/D2

題意:有兩個串,你能夠執行一次刪除操做,刪除一段連續的字符,刪除完以後第二個串依然是第一個串的子序列,求最大的能夠刪除的字符數

思路:  這個其實咱們枚舉刪除的一段字符是在第二個串的哪兩個字符中間便可,特別的判斷下一個整的序列的左邊右邊,固然一個串裏面可能出現屢次字符出現位置,由於咱們要求最大因此咱們直接求一個前綴,全部字符出現的第一次位置,一個後綴,全部字符出現的最後一次,這樣就能保證中間差距儘可能大,而後咱們枚舉刪除的字符在哪兩個之間求max便可

#include<bits/stdc++.h>
#define maxn 200005
#define mod 1000000007
using namespace std; typedef long long ll; char s1[maxn],s2[maxn]; ll b1[maxn],b2[maxn]; int main(){ cin>>s1>>s2; ll len1=strlen(s1); ll len2=strlen(s2); for(int i=0,j=0;i<len1;i++){ if(s1[i]==s2[j]){ b1[j]=i; j++; if(j==len2) break; } } for(int i=len1-1,j=len2-1;i>=0;i--){ if(s1[i]==s2[j]){ b2[j]=i; j--; if(j==-1) break; } } ll mx=0; mx=max(mx,b1[0]); mx=max(mx,len1-b1[len2-1]-1); mx=max(mx,b2[0]); mx=max(mx,len1-b2[len2-1]-1); for(int i=0;i<len2-1;i++){ mx=max(mx,b2[i+1]-b1[i]-1); } cout<<mx; return 0; }
View Code

本身的假題意:我一開始理解的是刪除後,第二個串是第一個串的子串,求最大的刪除字符數

思路:和上面同樣,要求一個前綴和後綴,不過我這個求得前綴和後綴有點區別,

舉個栗子:abcdddeffggg  與   bcdfg

那麼我就能夠組成得的幾種組合分別有   

bcdfg+""           b+cdfg         bc+dfg        bcd+fg      bcdf+g

分別記錄上面的子串第一次出現的位置,和最後出現的一次位置,而後和上面同樣求一個max,要記錄這些暴力確定不行,用n次kmp去找位置也不現實,可是其實咱們能夠只用一次kmp就能夠求出來,由於這些子串自己就是前綴的連續關係

能夠拿我這個假題意出個題,代碼在此奉上

#include<bits/stdc++.h>
#define maxn 200005
#define mod 1000000007
using namespace std; typedef long long ll; char s1[maxn],s2[maxn]; ll nxt[maxn],len1,len2; ll b1[maxn],b2[maxn]; void getnext(){ ll i=0,j=-1; nxt[0]=-1; while(i<len2){ if(j==-1||s1[i]==s2[j]){ nxt[++i]=++j; } else j=nxt[j]; } } void  kmp(char s1[],char s2[],ll b[]){ ll i=0,j=0; getnext(); while(i<len1){ if(j==-1||s1[i]==s2[j]){ i++;j++; if(b[j]==-1){ b[j]=i; } if(j==len2){ j=0; } } else j=nxt[j]; } } int main(){ cin>>s1>>s2; len1=strlen(s1); len2=strlen(s2); if(len1<=len2){ cout<<"0"; return 0; } for(int i=0;i<maxn;i++){ b1[i]=-1; b2[i]=-1; } kmp(s1,s2,b1); for(int i=0;i<len1/2;i++){ char t=s1[i]; s1[i]=s1[len1-i-1]; s1[len1-i-1]=t; } for(int i=0;i<len2/2;i++){ char t=s2[i]; s2[i]=s2[len2-i-1]; s2[len2-i-1]=t; } kmp(s1,s2,b2); for(int i=1;i<=len2;i++){ if(b1[i]!=-1) b1[i]--; } for(int i=1;i<=len2/2;i++){ ll t=b2[i]; b2[i]=b2[len2-i+1]; b2[len2-i+1]=t; } for(int i=1;i<=len2;i++){ if(b2[i]!=-1) b2[i]=len1-b2[i]; } ll mx=0; if(b1[len2]!=-1){ mx=max(b1[len2]-len2+1,len1-b1[len2]-1); } //cout<<mx<<"\n";
    if(b2[1]!=-1){ mx=max(mx,max(b2[1],len1-b2[1]-len2)); } //cout<<mx<<"\n";
    for(int i=1;i<len2;i++){ if(b1[i]!=-1&&b2[i+1]!=-1){ mx=max(mx,b2[i+1]-b1[i]-1); } } /*for(int i=1;i<=len2;i++){ cout<<b1[i]<<" "; } cout<<"\n"; for(int i=1;i<=len2;i++){ cout<<b2[i]<<" "; } cout<<"\n";*/ cout<<mx; return 0; } /* abcddbbbzle cdz */
View Code

 

 

E. Boxers

題目:https://codeforces.com/contest/1203/problem/E

題意:每一個數能夠變成本身和-1  +1的三種數,除了1,他不能變成比1更小的數,而後給你一組數,問你能夠變成幾個不一樣的數

思路:水題,直接從小到大排序,而後能儘可能小就儘可能小,打打標記便可

#include<bits/stdc++.h>
#define maxn 400005
#define mod 1000000007
using namespace std; typedef long long ll; ll a[maxn],n; ll vis[maxn]; int main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; sort(a+1,a+n+1); ll sum=0; for(int i=1;i<=n;i++){ if(vis[a[i]-1]==0&&a[i]!=1){ vis[a[i]-1]=1; sum++; } else if(vis[a[i]]==0){ vis[a[i]]=1; sum++; } else if(vis[a[i]+1]==0){ vis[a[i]+1]=1; sum++; } } cout<<sum; return 0; }
View Code

 

 

F1. Complete the Projects (easy version)

題目https://codeforces.com/contest/1203/problem/F1

題意:有n個項目,每一個項目有個最低要求資格,還有一個價值,會加到自身價值身上,最開始本身有一個價值,而後問是否能作完全部項目,作項目順序能夠本身排

思路:對於價值爲正的項目,很明顯咱們能夠直接從小到大的把項目作掉,這樣必定是最優的,對於負數來講,咱們排差值,差值大的,說明損耗對於自身的損耗較小,這樣才能保證本身還有能力作大項目,又能保證作完一個大項目後由於扣的太多而不能去作小項目

#include<bits/stdc++.h>
#define maxn 200005
#define mod 1000000007
using namespace std; typedef long long ll; ll n,m; struct sss { ll x,y; }a[maxn],b[maxn]; ll num1,num2; int cmp1(struct sss x,struct sss y){ return x.x<y.x; } int cmp2(struct sss x,struct sss y){ if(x.x+x.y==y.x+y.y) return x.x>y.x; return x.x+x.y>y.x+y.y; } int main(){ cin>>n>>m; ll x,y; for(int i=0;i<n;i++){ cin>>x>>y; if(y>=0){ a[num1].x=x; a[num1++].y=y; } else{ b[num2].x=x; b[num2].y=y; num2++; } } sort(a,a+num1,cmp1); sort(b,b+num2,cmp2); int flag=0; for(int i=0;i<num1;i++){ if(m>=a[i].x) m+=a[i].y; else{ flag=1; break; } } if(flag) printf("NO"); else{ for(int i=0;i<num2;i++){ if(m>=b[i].x) m+=b[i].y; else{ flag=1; break; } } if(!flag&&m>=0) printf("YES"); else printf("NO"); } return 0; } 
View Code

 

F2. Complete the Projects (hard version)

題目:https://codeforces.com/contest/1203/problem/F2

題意:和F1同樣,可是這個是問能作的最多項目數是多少

思路:對於F1來講直接按差值排,是爲了完成全部項目,因此順序大的小的在前無所謂,可是這個有可能不能完成,可是能夠換個方向多完成幾個,對於這種狀況較多複雜度又要求高的咱們就會想到用dp

咱們直接對於每一個項目來講的話,考慮當前項目取或者不取,可是咱們又須要其餘價值的最優值,因此其實咱們就能夠轉化成一個01揹包,dp[i][j]表明前i件裏面j價值能取得最多項目數是多少

#include<bits/stdc++.h>
#define maxn 100005
#define mod 1000000007
using namespace std; typedef long long ll; struct sss{ ll x,y; }a[maxn],b[maxn]; ll n,m,num1=1,num2=1; ll dp[105][60005]; int cmp1(struct sss x,struct sss y){ return x.x<y.x; } int cmp2(struct sss x,struct sss y){ return x.x+x.y>y.x+y.y; } int main(){ scanf("%lld%lld",&n,&m); for(int i=0;i<n;i++){ ll x,y; scanf("%lld%lld",&x,&y); if(y>=0){ a[num1].x=x; a[num1++].y=y; } else{ b[num2].x=x; b[num2++].y=y; } } sort(a+1,a+num1,cmp1); sort(b+1,b+num2,cmp2); ll ans=0; for(int i=1;i<num1;i++){ if(m>=a[i].x){ ans++; m+=a[i].y; } else break; } memset(dp,0,sizeof(dp)); for(int i=1;i<num2;i++){ for(int j=m;j>=0;j--){ if(j+b[i].y>=0&&j>=b[i].x) dp[i][j+b[i].y]=max(dp[i-1][j+b[i].y],dp[i-1][j]+1); else dp[i][j]=max(dp[i][j],dp[i-1][j]); } } ll mx=0; for(int i=0;i<=m;i++){ mx=max(mx,dp[num2-1][i]); } cout<<ans+mx; }
View Code
相關文章
相關標籤/搜索