Codeforces Round 895 (Div. 3)

\(A. Two Vessels\)

一开始我以为那个 \(c\) 桶只能装满,看了好久。
范围内的任意容量都可以取的话,那么只要看需要转移多少量,然后看需要多少次。

void solve(){
    int n=read(),m=read(),k=read();
    double nd=abs(n-m)*1.0/2;
    int ans=ceil(nd/k);
    cout<<ans<<'\n';
    //puts(ans>0?"YES":"NO");
    //puts(ans>0?"Yes":"No");
}

\(B. The Corridor or There and Back Again\)

计算每个房间走过之后能最多向后走几个房间,向后遍历的时候取最小值。

void solve(){
    int n=read();
    vector<int>a(10000,inf);
    for(int i=1;i<=n;i++){
        int x=read(),y=read();
        a[x]=min((y-1)/2,a[x]);
    }
    int now=inf;
    for(int i=1;i<=10000&&i<=now;i++){
        now=min(a[i]+i,now);
    }
    cout<<now<<'\n';
    //puts(ans>0?"YES":"NO");
    //puts(ans>0?"Yes":"No");
}

\(C. Non-coprime Split\)

如果一个数能被整除,就可以被分成这么多份,那么只要每份的个数大于 \(1\) 就可以做到题目要求的 \(gcd\ne1\)

void solve(){
    int l=read(),r=read();
    for(int i=l;i<=r;i++){
        int x=i;
        for(int j=2;j*j<=x;j++){
            if(x%j==0){
                cout<<x/j<<" "<<x-x/j<<'\n';
                return ;
            }
        }
    }
    cout<<-1<<'\n';
    //puts(ans>0?"YES":"NO");
    //puts(ans>0?"Yes":"No");
}

\(D. Plus Minus Permutation\)

肯定把最大值放在加的地方,最小值放在减的地方,不知道知道的只有放多少个。
显然能起作用的加数是 \(n/x-n/lcm(x,y)\) ,减数同理。
知道个数之后只需要求和即可。

int get_sum(int x,int y){
    return (x+y)*(y-x+1)/2;
}
int gcd(int a, int b){
    return b ? gcd(b, a % b) : a;
}

void solve(){
    int n=read(),a=read(),b=read();
    int g=a*b/(gcd(a,b));
    b=n/b-n/g;
    a=n/a-n/g;
    int ans=get_sum(n-a+1,n);
    ans-=get_sum(1,b);
    cout<<ans<<'\n';
    //puts(ans>0?"YES":"NO");
    //puts(ans>0?"Yes":"No");
}

\(E. Data Structures Fan\)

每次修改都是直接异或上区间和就行了,那么修改和查询的复杂度都是 \(O(1)\)

int sum[N],a[N];
void solve(){
    int n=read(),ans0=0,ans1=0;
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    string s;
    cin>>s;
    s=' '+s;
    for(int i=1;i<=n;i++){
        if(s[i]=='0')ans0^=a[i];
        else ans1^=a[i];
    }
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1]^a[i];
    }
    int q=read();
    while(q--){
        int op=read();
        if(op==1){
            int x=read(),y=read();
            int chg=sum[y]^sum[x-1];
            ans1^=chg;
            ans0^=chg;
        }else{
            int x=read();
            if(x==0)cout<<ans0<<' ';
            else cout<<ans1<<' ';
        }
    }
    cout<<'\n';
    //puts(ans>0?"YES":"NO");
    //puts(ans>0?"Yes":"No");
}

\(F. Selling a Menagerie\)

如果把入度为 \(0\) 的点不断删掉,那么将会变成一个基环图,而且先删掉这样的点肯定是最优的。
对于一个环,可以有一个点被计算一次,其他点计算两次,显然选择最小的点计算一次,用优先队列跑一下。

void solve(){
    int n=read();
    vector<int>a(n+1),r(n+1),o(n+1),fa(n+1),vis(n+1);
    vector<int>res;
    for(int i=1;i<=n;i++){
        int x=read();
        fa[i]=x;
        r[x]++;
        o[i]++;
    }
    for(int i=1;i<=n;i++)a[i]=read();
    int ans=0;
    for(int i=1;i<=n;i++){
        if(r[i]==0&&vis[i]==0){
            r[fa[i]]--,ans+=a[i],vis[i]=1,res.push_back(i);
            int nex=fa[i];
            while(r[nex]==0){
                r[fa[nex]]--,ans+=a[nex],vis[nex]=1,res.push_back(nex);
                nex=fa[nex];
            }
        }else pq.push(make_pair(a[i],i));
    }

    while(pq.size()){
        int x=pq.top().first,y=pq.top().second;
        pq.pop();
        if(vis[y]){
            continue;
        }
        ans+=x;
        int nex=fa[y];
        while(vis[nex]==0){
            ans+=a[nex]*2;
            res.push_back(nex);
            vis[nex]=1;
            nex=fa[nex];
        }
    }    for(auto x:res){
        cout<<x<<" ";
    }
    cout<<'\n';
    //puts(ans>0?"YES":"NO");
    //puts(ans>0?"Yes":"No");
}

\(G.Replace With Product\)

首先显然的,左右两侧的 \(1\) 都不应在乘的区间里。后面所说的不再考虑这些数字。
剩下的数字如果计算乘积可能用 \(longlong\) 存不下,那么会发现,如果乘积一旦大于1e9就说明存在平凡解,即所有余下的数字。否则就说明不为 \(1\) 的点只有 \(log_n^{1e9}\) 个,这时候穷举所有情况即可。

int a[N];
void solve(){
    int n=read(),sum=0;
    for(int i=1;i<=n;i++){
        a[i]=read();
        sum+=a[i];
    }
    int l=1,r=n;
    for(int i=1;i<=n&&l<r;i++){
        if(a[i]==1)l++;
        else break;
    }
    for(int i=n;i>=1&&r>l;i--){
        if(a[i]==1)r--;
        else break;
    }
    int allji=1;
    for(int i=l;i<=r;i++){
        allji*=a[i];
        if(allji>=1e9){
            cout<<l<<" "<<r<<'\n';
            return ;
        }
    }
    vector<int>vec;
    for(int i=1;i<=n;i++){
        if(a[i]>1)vec.push_back(i);
    }
    int ansl=1,ansr=1,ans=sum;
    for(int i=0;i<vec.size();i++){
        int l=vec[i],res=1,s=0;
        for(int j=i;j<vec.size();j++){
            int r=vec[j];
            res*=a[r];
            s+=a[r]-1;
            int v=sum-(r-l+1)-s+res;
            if(v>ans){
                ans=v;
                ansl=l;
                ansr=r;
            }
        }
    }
    cout<<ansl<<" "<<ansr<<'\n';
    //puts(ans>0?"YES":"NO");
    //puts(ans>0?"Yes":"No");
}
posted @ 2023-09-08 00:57  EdGrass  阅读(167)  评论(1)    收藏  举报