Codeforces Round #689题解

A题

循环构造bac即可,因为题目是小于等于,我看成了等于所以构造的复杂了点

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int main(){
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--){
        int n,k;
        cin>>n>>k;
        string res="";
        int i;
        for(i=0;i<k;i++){
            res+='a';
        }
        n-=k;
        int x=0;
        for(i=0;i<n;i++){
            if(x%3==0){
                res+='b';
            }
            else if(x%3==1){
                res+='c';
            }
            else{
                res+='a';
            }
            x++;
        }
        cout<<res<<endl;
 
    }
}
View Code

B题

直接枚举三维加上一些剪枝,复杂度能够接受

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int sum[1010][1010];
string s[N];
int main(){
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        int i,j;
        memset(sum,0,sizeof sum);
        for(i=1;i<=n;i++){
            cin>>s[i];
            s[i]=" "+s[i];
        }
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                sum[i][j]=sum[i][j-1]+(s[i][j]=='*');
            }
        }
        int ans=0;
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                for(int k=i;k<=n;k++){
                    if(j+k-i>m||j-k+i<1)
                        break;
                    if(sum[k][j+k-i]-sum[k][j-k+i-1]!=2*(k-i)+1)
                        break;
                    ans++;
                }
            }
        }
        cout<<ans<<endl;
    }
}
View Code

C题

容斥思想,找到后缀中最前面的使得后面都是按序,这样答案就是1-前面都不符合的情况

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int a[N];
int p[N];
int main(){
    //ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        int i;
        for(i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        int last=n+1;
        for(int i=n;i>0;i--){
            if(a[i]==i){last=i;}
            else break;
        }
        double ans=1;
        for(i=1;i<=m;i++){
            int pos;
            double cnt;
            scanf("%d%lf",&pos,&cnt);
            if(pos>=last-1){
                ans=ans*(1-cnt);
            }
        }
        int sign=0;
        for(i=2;i<=n;i++){
            if(a[i]-a[i-1]!=1){
                sign=1;
            }
        }
        if(!sign){
            cout<<"1.000000"<<endl;
        }
        else
        printf("%.6f
",1-ans);
    }
}
View Code

D题

首先排序,那么之后就是一种分治的思想,根据mid不断往两边,用一个map存所有的可能性,这里需要二分一下边界,之后判断所有情况即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n,q;
int a[N];
int b[N];
map<ll,int> m1;
ll sum[N];
vector<int> num;
void solve(int l,int r){
    if(l>r)
        return ;
    if(l==r){
        m1[a[l]]=1;
        return ;
    }
    int mid=(a[l]+a[r])/2;
    int l1=l,r1=r;
    while(l1<r1){
        int tmp=l1+r1+1>>1;
        if(a[tmp]<=mid)
            l1=tmp;
        else
            r1=tmp-1;
    }
    m1[(sum[l1]-sum[l-1])]=1;
    m1[(sum[r]-sum[l1])]=1;
    if(a[l1]!=a[l]||(l1==l))
        solve(l,l1);
    if(a[l1+1]!=a[r]||(l1+1==r))
        solve(l1+1,r);
}
int main(){
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--){
        m1.clear();
        cin>>n>>q;
        int i;
        for(i=1;i<=n;i++){
            cin>>a[i];
            sum[i]=0;
        }
        sum[n+1]=0;
        for(i=1;i<=q;i++){
            cin>>b[i];
        }
        sort(a+1,a+1+n);
        for(i=1;i<=n;i++){
            sum[i]=a[i]+sum[i-1];
        }
        solve(1,n);
        m1[sum[n]]=1;
        for(i=1;i<=q;i++){
            if(m1[b[i]]){
                cout<<"Yes"<<endl;
            }
            else{
                cout<<"No"<<endl;
            }
        }
    }
}
View Code

E题

观察到数据范围这么大,一般都会有规律在里面,首先比较容易想到的是分类讨论

分x和y的关系,x>y容易讨论,现在重点讨论x<y

第一步的贪心比较好想,因为y>x所以我们要防止的就是不要溢出,因为所有的小于下界都可以通过先+y,再-x控制

那么贪心的思路就是不断-x,在不能减的时候+y,这样是最不可能溢出的情况。

但是问题是现在的数据有点大,所以肯定有突破口,观察数据范围,x只有1e6,并且我们每次都是一直-x到不行

所以可以按x的模数分类,到达过已经判定合法的状态的情况下,那么一定是yes

剩下就是讨论溢出的问题了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
int st[N];
int main(){
    ios::sync_with_stdio(false);
    ll k,l,r,t,x,y;
    cin>>k>>l>>r>>t>>x>>y;
    if(x>y){
        if(k+y>r){
            t--;
            k-=x;
        }
        if(k<l){
            cout<<"No"<<endl;
            return 0;
        }
        ll tmp=(k-l)/(x-y);
        if(t<=tmp){
            cout<<"Yes"<<endl;
        }
        else{
            cout<<"No"<<endl;
        }
    }
    else{
        while(1){
            if(st[k%x]){
                cout<<"Yes"<<endl;
                return 0;
            }
            t-=(k-l)/x;
            if(t<=0){
                cout<<"Yes"<<endl;
                return 0;
            }
            k=k-((k-l)/x*x);
            st[k%x]=1;
            k+=y;
            if(k>r){
                cout<<"No"<<endl;
                return 0;
            }
            if(k-x<l){
                cout<<"No"<<endl;
                return 0;
            }
        }
    }
}
View Code

 F题

参考的某谷的思路,首先肯定是分类讨论,其他的讨论都比较简单,主要是+*的情况

这种情况下,我们可以根据0划分成独立贡献

那么再根据1讨论情况,对于这里要使用dp,但是普通dp一个是超时一个是炸ll

因此肯定要有什么方法解决他,普通的dp思路很清晰,也很有道理,所以我们思考是否有一些约束性条件

只要乘积和大于1e9,那么这段全部的肯定是乘法,这样就能降低复杂度了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
int pre[N],pl[N],pr[N],pm[N];
int a[N];
map<char,int> m1;
int ans[N];
ll f[N];
void solve(int l,int r){
    int lst=l-1;
    ll sign=1;
    int i;
    int idx=0;
    for(i=l;i<=r;i++){
        if(a[i]==1){
            if(lst+1<=i-1) pl[++idx]=lst+1,pr[idx]=i-1,pm[idx]=sign;
            sign=1;
            lst=i;
        }
        else{
            sign*=a[i];
            if(sign>1e9)
                sign=1e9;
        }
    }
    if(lst!=r){
        pl[++idx]=lst+1,pr[idx]=r,pm[idx]=sign;
    }
    pr[0]=l-1;
    for(i=1;i<=idx;i++){
        f[i]=0;
    }
    sign=1;
    for(i=1;i<=idx;i++){
        sign*=pm[i];
        if(sign>1e9){
            sign=1e9;
            break;
        }
    }
    if(sign==1e9){
        pre[idx]=1;
    }
    else{
        for(int i=1;i<=idx;i++){
            ll mul=1;
            for(int j=i;j>=1;j--){
                mul*=pm[j];
                if(f[i]<f[j-1]+pl[j]-pr[j-1]-1+mul){
                    f[i]=f[j-1]+pl[j]-pr[j-1]-1+mul;
                    pre[i]=j;
                }
            }
        }
    }
    for(int i=l;i<pl[1];i++) ans[i]=1;
    for(int i=pr[idx];i<r;i++) ans[i]=1;
    int cur=idx;
    while(cur){
        int t=pre[cur];
        for(int i=pr[t-1];i<pl[t];i++) ans[i]=1;cur=t-1;
    }

}
int main(){
    ios::sync_with_stdio(false);
    int n;
    cin>>n;
    int i;
    for(i=1;i<=n;i++){
        cin>>a[i];
    }
    m1['+']=0,m1['-']=1,m1['*']=2;
    string s;
    cin>>s;
    s=" "+s;
    int sign=0;
    for(i=1;i<(int)s.size();i++){
        sign|=(1<<m1[s[i]]);
    }
    if(sign==1||sign==2||sign==4){
        for(int i=1;i<=n;i++){
            cout<<a[i];if(i!=n) cout<<s[1];
        }
    }
    else if(sign==3){
        for(int i=1;i<=n;i++){
            cout<<a[i];if(i!=n) cout<<"+";
        }
    }
    else if(sign==6){
        bool hav=0;cout<<a[1];
        for(int i=2;i<=n;i++){
            if(!a[i]&&!hav) hav=1,cout<<"-";
            else cout<<"*";
            cout<<a[i];
        }
    }
    else{
        for(i=1;i<=n;i++){
            if(!a[i]){
                if(i!=1) ans[i-1]=1;
                if(i!=n) ans[i]=1;
            }
        }
        int lst=0;
        for(i=1;i<=n;i++){
            if(!a[i]){
                solve(lst+1,i-1),lst=i;
            }
        }
        solve(lst+1,n);
        for(i=1;i<n;i++){
            cout<<a[i];
            if(ans[i]){
                cout<<"+";
            }
            else{
                cout<<"*";
            }
        }
        cout<<a[n]<<endl;
    }
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/14296726.html