zoukankan      html  css  js  c++  java
  • Codeforces Round #592 (Div. 2)

    (一道sb题卡了我40min,成功GG)

    A:

    送分题。sry说他没看懂所以先开D然后成功吊打我,看来Div2不能顺着开题。。

    #include<bits/stdc++.h>
    #define maxn 100005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    
    using namespace std;
    
    inline int read(){
        int x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    int main(){
        int t=read();
        while(t--){
            int a=read(),b=read(),c=read(),d=read(),k=read();
            int t1=a/c+(a%c?1:0),t2=b/d+(b%d?1:0);
            if(t1+t2<=k) cout<<t1<<" "<<t2<<endl; 
            else cout<<-1<<endl;
        }
        return 0;
    }
    A

    B:

    送分题。

    #include<bits/stdc++.h>
    #define maxn 1005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    
    using namespace std;
    char str[maxn];
    
    inline int read(){
        int x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    int main(){
        int T=read();
        while(T--){
            int n=read();
            cin>>str+1;
            int l=0,r=0,ans=n,flag=0;
            for(int i=1;i<=n;i++){
                if(str[i]=='1' && !flag) l=i,flag=1;
                if(str[i]=='1') ans=max(ans,max(i*2,(n-i+1)*2));
            }
            for(int i=n;i>=1;i--)
                if(str[i]==1)
                    {r=i;break;} 
            if(!l) cout<<ans<<endl;
            else if(l==r) cout<<ans<<endl;
            else cout<<max(ans,(r-l+1)*2+max(l-1,n-r))<<endl;
        }
        return 0;
    }
    B

    C:

    回收开头。

    题意简洁明了,求方程$ax+by=c$的一组正整数解,满足$x+yleq n$

    数据范围$nleq 10^{12},cleq 10^{17},b<aleq 10^{5}$

    花了10min写了一个exgcd,然后wa on 5。当时我就自闭了。

    注意到exgcd求出答案后要乘$frac{c}{gcd(a,b)}$,而这个会爆long long,cf又好像不支持__int128。

    换一种思路,能不能求一个x使得$axequiv c(mod b)$呢?

    首先我们容易发现,至多枚举b个x就会出现0。

    如果我们将x从大往小枚举,那么当第一次出现一个x满足题意时,这个答案一定是a最多且b最少的。

    此时由于$a>b$,那么$x+y$的值一定是最小的。

    或者,注意到$d>w$,那么必定有$y>w$,或者说求出y后需要$mod w$

    因为每w个d的贡献等于d个w的贡献,而后者用的个数较少。

    那么由于$d,wleq 10^5$,枚举y求解即可。

    (当然你把c先膜一下然后做,最后再加回来也是可以的,我还是太蔡了)

    #include<bits/stdc++.h>
    #define maxn 100005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    
    using namespace std;
    
    inline ll read(){
        ll x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    int main(){
        ll n=read(),p=read(),a=read(),b=read(),x=p/a,T=maxn;
        while(T--){
            if((p-x*a)%b==0){
                if(x<0 || x+(p-x*a)/b>n){cout<<-1<<endl;return 0;}
                else{cout<<x<<" "<<(p-x*a)/b<<" "<<n-(x+(p-x*a)/b)<<endl;return 0;}
            }
            x--;
        }
        cout<<-1<<endl;
        return 0;
    }
    C

    D:

    送分题,注意到只有一条链满足题意就完事了。

    (那么div2开题应该从D开始开?)

    #include<bits/stdc++.h>
    #define maxn 100005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    
    using namespace std;
    int N,hd[maxn],to[maxn<<1],nxt[maxn<<1],cnt,siz[maxn],deg[maxn];
    ll cst[3][maxn],dp[maxn][3][3];
    int from[maxn][3][3][2],cl[maxn];
    
    inline ll read(){
        ll x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    inline void addedge(ll u,ll v){
        to[++cnt]=v,nxt[cnt]=hd[u],hd[u]=cnt;
    }
    
    inline void dfs(int u,int fa){
        int son=0;
        //cout<<u<<":"<<fa<<endl;
        for(int i=hd[u];i;i=nxt[i])
            if(to[i]!=fa) son=to[i],dfs(son,u);
        //cout<<son<<endl;
        if(!son){
            for(int i=0;i<3;i++) 
                dp[u][i][i]=cst[i][u];
            return;
        }
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                for(int k=0;k<3;k++)
                    if(dp[u][i][j]>dp[son][j][k]+cst[i][u] && i!=j && i!=k)
                        dp[u][i][j]=dp[son][j][k]+cst[i][u],from[u][i][j][0]=j,from[u][i][j][1]=k;
        return;
    }
    
    inline void find(int u,int fa,int x,int y){
        cl[u]=x;
        int son=0;
        for(int i=hd[u];i;i=nxt[i])
            if(to[i]!=fa) son=to[i];
        if(son) find(son,u,from[u][x][y][0],from[u][x][y][1]);
        return;
    }
    
    int main(){
        memset(dp,127,sizeof(dp));
        N=read();
        for(ll k=0;k<3;k++)
            for(ll i=1;i<=N;i++) cst[k][i]=read();
        for(ll i=1;i<=N-1;i++){
            ll u=read(),v=read();
            addedge(u,v),addedge(v,u);
            deg[u]++,deg[v]++;
        }
        bool flag=0;
        ll num=0,rt=0;
        for(ll i=1;i<=N;i++){
            if(deg[i]>=3){flag=1;break;}
            if(deg[i]==1) rt=i;
        }
        if(flag) cout<<-1<<endl;
        else{
            dfs(rt,0);
            ll ans=(1ll<<62),r1=0,r2=0;
            for(int i=0;i<3;i++)
                for(int j=0;j<3;j++)
                    if(dp[rt][i][j]<ans)
                        ans=dp[rt][i][j],r1=i,r2=j;
            find(rt,0,r1,r2);
            cout<<ans<<endl;
            for(int i=1;i<=N;i++)
                cout<<cl[i]+1<<" ";
            cout<<endl;
        }
        return 0;
    }
    D

    E:

    送分题,排个序之后从两边往中间依次考虑即可。

    我都不知道这题为啥不出到B。

    #include<bits/stdc++.h>
    #define maxn 100005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
     
    using namespace std;
    ll N,K,A[maxn];
     
    inline ll read(){
        ll x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
     
    int main(){
        N=read(),K=read();
        for(ll i=1;i<=N;i++) A[i]=read();
        sort(A+1,A+1+N);
        ll ans=0;
        for(ll i=1;i<=N;i++){
            ll l=i,r=N-i+1;
            if(l>r){ans=0;break;}
            if(K>=(A[l+1]-A[l])*i) K-=(A[l+1]-A[l])*i,l++;
            else{ans=A[r]-(A[l]+(K/i));break;}
            if(K>=(A[r]-A[r-1])*i) K-=(A[r]-A[r-1])*i,r--;
            else{ans=(A[r]-(K/i))-A[l];break;}
        }
        ans=max(ans,1ll*0);
        cout<<ans<<endl;
        return 0;
    }
    E

    F:

    本场最难写的送分题。

    注意到一个长度超过2的相同字符串一定不会改变。

    于是我们统计出所有这样的不变子串,那么相邻两个子串间一定是01交替出现。

    每次变换相当于将每个不变子串向左右扩张一位。

    如果和这个子串相邻的也是不变子串那么停止扩张。

    注意把数组开大。

    #include<bits/stdc++.h>
    #define maxn 1000005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    
    using namespace std;
    int N,k; char str[maxn],res[maxn],ans[maxn];
    pair<int,int> p[maxn];
    
    inline int read(){
        int x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    inline char cn(char a){
        if(a=='B') return 'W';
        else return 'B';
    }
    
    int main(){
        N=read(),k=read();
        cin>>str+1;
        for(int i=1;i<=N;i++) str[N+i]=str[i];
        for(int i=1;i<=N;i++) str[2*N+i]=str[i];
        str[0]=str[N];
        int s=0,tot=0;
        for(int i=1;i<=N;i++)
            if(str[i+1]==str[i] && str[i-1]!=str[i])
                {s=i;break;}
        if(!s){
            if(str[1]==str[2]){for(int i=1;i<=N;i++) cout<<str[i];cout<<endl;}
            else if(k%2){for(int i=1;i<=N;i++) cout<<cn(str[i]);cout<<endl;}
            else{for(int i=1;i<=N;i++) cout<<str[i];cout<<endl;}
            return 0;
        }
        for(int i=s;i<=s+N-1;){
            int j=i; 
            while(str[j]==str[j+1]&&j+1<=s+N-1) j++;
            if(j==i){i=j+1;continue;} 
            p[++tot]=make_pair(i,j),i=j+1;
        }
        p[++tot]=p[1],p[tot].first+=N,p[tot].second+=N;
        for(int j=2;j<=tot;j++){
            int l=p[j-1].second+1,r=p[j].first-1;
            if(l<=r){
                if(str[p[j].first]==str[p[j-1].first]){
                    char co=str[p[j].first];
                    if(k*2>=(r-l+1)) for(int i=l;i<=r;i++) res[i]=co; 
                    else{
                        for(int i=l;i<=l+k-1;i++) res[i]=co;
                        for(int i=r;i>=r-k+1;i--) res[i]=co;
                        for(int i=l+k;i<=r-k;i++) res[i]=(k%2)?cn(str[i]):str[i];
                    }
                }
                else{
                    char co=str[p[j].first],coo=str[p[j-1].first];
                    if(k*2>=(r-l+1)){
                        int num=(r-l+1)>>1;
                        for(int i=l;i<=(l+r)>>1;i++) res[i]=coo;
                        for(int i=r;i>((l+r)>>1);i--) res[i]=co;
                    } 
                    else{
                        for(int i=l;i<=l+k-1;i++) res[i]=coo;
                        for(int i=r;i>=r-k+1;i--) res[i]=co;
                        for(int i=l+k;i<=r-k;i++) res[i]=(k%2)?cn(str[i]):str[i];
                    }
                }
            }
            for(int i=p[j-1].first;i<=p[j-1].second;i++) res[i]=str[p[j-1].first];
        }
        for(int i=s;i<=s+N-1;i++) ans[(i-1)%N+1]=res[i];
        for(int i=1;i<=N;i++) cout<<ans[i];
        cout<<endl;
        return 0;
    }
    F

    G:

    需要想一下的送分题。

    容易发现两个序列都顺着排答案最小,一个顺着排一个倒着排最大。

    那么如果k小于最小的答案直接-1,大于最大的答案直接最大。

    对于其他的情况,我们先固定A是顺着排的,然后考虑第i个位置的max是A还是B。

    假如是A,那么将B里面当前没用的最小的放在这里,容易证明这个东西一定小于A。

    假如是B,注意到任意$[0,K-n imes(n-1)]$之间的数一定能用1-n凑出来。(因为仅用1-n之间2的幂次就能凑出来了)

    那么从左向右依次考虑B中的最大数填在哪即可实现凑出来的过程,此时答案一定为K。

    #include<bits/stdc++.h>
    #define maxn 1000005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    
    using namespace std;
    ll N,K,A[maxn];
    
    inline ll read(){
        ll x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    int main(){
        N=read(),K=read();
        ll mx=0,ans=0;
        for(ll i=1;i<=N;i++) ans+=i,mx+=max(i,N-i+1);
        if(K<ans){cout<<-1<<endl;return 0;}
        if(K>=mx){
            cout<<mx<<endl;
            for(ll i=1;i<=N;i++) cout<<i<<" ";cout<<endl;
            for(ll i=1;i<=N;i++) cout<<N-i+1<<" ";cout<<endl;
            return 0;
        }
        ll l=1,r=N;
        for(ll i=1;i<=N;i++){
            if(K>=ans+r-i && r-i>=0) ans+=r-i,A[i]=r,r--;
            else A[i]=l,l++;
        }
        cout<<ans<<endl;
        for(ll i=1;i<=N;i++) cout<<i<<" ";cout<<endl;
        for(ll i=1;i<=N;i++) cout<<A[i]<<" ";cout<<endl;
        return 0;
    }
    G

    总结:

    1.当你一个题写完后wa on pretest而且并不知道为什么,那么如果你没有读错题就果断跳过。

    2.Div2可以考虑倒着开题,或者中间开题。

    3.能请一个人来帮你口胡总是好的。

  • 相关阅读:
    暗通道先验去雾算法及其几何意义的解释
    几种去雾算法介绍
    大气散射模型的推导
    散射介质环境中偏振成像图像的去散射方法
    最近的笔面试题知识整理一
    了解 Web Service
    数梦工厂笔试题回顾一----finally在return之后执行还是之前?
    Struts2的配置文件的加载
    Struts2中Action配置
    struts.xml的语法
  • 原文地址:https://www.cnblogs.com/YSFAC/p/11668798.html
Copyright © 2011-2022 走看看