A. Circle of Students     

题目:https://codeforces.com/contest/1203/problem/A

题意:一堆人坐成一个环,问能否按逆时针或者顺时针正好是 1-n的顺序

思路:水题,把数组开两倍,或者标记当前位置都可以

#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/B

题意:有4*n根木棍,现在问能否组成n个面积相等的矩形

思路:首先我们组成第一个矩形肯定是最小和最大,然后第二个是次小和次大.....所以我们对木棒排序,然后两个指针判是否可行即可

 #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 Divisors

题目:https://codeforces.com/contest/1203/problem/C

题意:有一个序列,现在求一个数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