Codeforces Round 1065 (Div. 3) A-G

A. Shizuku Hoshikawa and Farm Legs

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
	int n;
    cin>>n;

    if(n&1){
        cout<<0<<endl;
        return;
    }

    cout<<n/4+1<<endl;
}

signed main(){

	ios::sync_with_stdio(0);
	cin.tie(0);

	int t=1;
	cin>>t; 
	
	while(t--){
		solve(); 
	}

}

B. Yuu Koito and Minimum Absolute Sum

观察 \(b\) 数组求和的式子,发现只有 \(a_1,a_n\) 是有用的

所以其他位置填 \(0\),分情况讨论一下 \(a_1,a_n\) 即可

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
	int n;
    cin>>n;

    vector<int> a(n+1);

    for(int i=1;i<=n;i++){
        cin>>a[i];

        if(i!=1 && i!=n && a[i]==-1){
            a[i]=0;
        }
    }

    if(a[1]==-1 && a[n]==-1){
        a[1]=0,a[n]=0;
    }
    else if(a[1]==-1){
        a[1]=a[n];
    }
    else if(a[n]==-1)a[n]=a[1];

    cout<<abs(a[n]-a[1])<<endl;

    for(int i=1;i<=n;i++) cout<<a[i]<<" ";

    cout<<endl;


}

signed main(){

	ios::sync_with_stdio(0);
	cin.tie(0);

	int t=1;
	cin>>t; 
	
	while(t--){
		solve(); 
	}

}

C2. Renako Amaori and XOR Game (hard version)

可以从高位到低位去贪心的计算

对于某一位,如果两个数组中这一位的数量和为偶数,则不管怎么交换,\(a,b\) 数组这一位的异或和都相同,此时这一位没有影响,看下一位

如果为奇数,则需要去找最后一个位置,满足 \(a,b\) 两个数,有一个数这一位为 \(1\),另一个数这一位为 \(0\)。谁能操作这个位置,谁就赢

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n;
    cin>>n;

    vector<int> a(n+1),b(n+1);

    for(int i=1;i<=n;i++){
        cin>>a[i];
    }

    for(int i=1;i<=n;i++){
        cin>>b[i];
    }

    for(int k=30;k>=0;k--){
        int cnt=0;
        for(int i=1;i<=n;i++){
            
            // if(((a[i]>>k) & 1)==((b[i]>>k) & 1)){
            //     continue;
            // }
            // else cnt++;
            cnt+=((a[i]>>k) & 1);
            cnt+=((b[i]>>k) & 1);
        }

        if(cnt%2==0) continue;

        for(int i=n;i>=1;i--){
            if(((a[i]>>k) & 1)!=((b[i]>>k) & 1)){
                if(i&1){
                    cout<<"Ajisai";
                }
                else{
                    cout<<"Mai";
                }
                cout<<endl;
                return;
            }
        }
    }

    cout<<"Tie"<<endl;


}

signed main(){

	ios::sync_with_stdio(0);
	cin.tie(0);

	int t=1;
	cin>>t; 
	
	while(t--){
		solve(); 
	}

}

F. Rae Taylor and Trees (hard version)

首先,如果存在位置 \(i\),满足前缀最小值大于后缀最大值,则这个位置的两边无法联通,不能构成树。

否则,可以给出构造方案:

可以找到最小值 \(pos=i\),让最小值去连接 \(i\) 右面的所有数字。

再让 \(pos=i-1\) 的前缀最小值去连接 \(pos=i\) 的后缀最大值

再找到 \(1-(i-1)\) 的最小值 \(j\),令 \(i=j\),不断进行上面的操作,直到连接整个树

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
	int n;
    cin>>n;

    vector<int> a(n+1),premin(n+1,inf),sufmax(n+2);
	vector<int> pos(n+1);

    for(int i=1;i<=n;i++){
        cin>>a[i];
        premin[i]=min(premin[i-1],a[i]);
		pos[a[i]]=i;
    }

    for(int i=n;i>=1;i--){
        sufmax[i]=max(sufmax[i+1],a[i]);
    }

    for(int i=1;i<n;i++){
        if(premin[i]>sufmax[i+1]){
            cout<<"No\n";
            return;
        }
    }

    cout<<"Yes\n";

	vector<pii> ans;

	int p=n;
	while(p>1){
		int tmp=pos[premin[p]];
		for(int i=tmp+1;i<=p;i++){
			ans.push_back({a[tmp],a[i]});
		}
		if(tmp>1) ans.push_back({premin[tmp-1],sufmax[tmp]});
		p=tmp-1;
	}

	for(auto [x,y]:ans){
		cout<<x<<" "<<y<<endl;
	}
}

signed main(){

	ios::sync_with_stdio(0);
	cin.tie(0);

	int t=1;
	cin>>t; 
	
	while(t--){
		solve(); 
	}

}

E. Anisphia Wynn Palettia and Good Permutations

最优的方式是,使用 \(2\)\(3\) 的倍数,构造:

2_22_22_23_3 这样的,数列,其中 \(2\) 代表 \(2\) 的倍数, \(3\) 代表 \(3\) 的倍数

因为在 \(1\)\(n\) 中,\(2\) 的倍数的个数是 \(n/2\),是\(3\) 的倍数且不是 \(2\) 的倍数的数字个数是 \(n/6\)

相加刚好是 \((2*n)/3\),中间隔出来的空位刚好可以填其他数字

赛时没有发现只使用 \(2,3\) 即可,把 \(1\)\(n\) 所有的质因数都弄了出来,写了一坨,其实代码很好写

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

const int mx=2e5;
vector<int> lp(mx+1),ps(mx+1);
//lp:最小质因子,ps:不同质因子个数
vector<int> primes;

void init(){
    for(int i=2;i<=mx;i++){
        if(!lp[i]){
            lp[i] = i;
            primes.push_back(i);
        }
        for(int p:primes){
            if(p>lp[i]||i*p>mx) break;
            lp[i*p]=p;
        }
    }
}

void solve(){
    int n;
    cin>>n;

    vector<int> a(n+1);
    int idx=1;
    map<int,int> st;

    vector<vector<int>> t(n+1);

    if(n<=12){
        for(int i=1;i<=n;i++){
            cout<<i<<" ";
        }
        cout<<endl;
        return;
    }
    
    for(auto val:primes){
        for(int i=1;val*i<=n;i++){
            if(idx>n) break;
            if(st[val*i]) continue;
            
            st[val*i]=1;
            t[val].push_back(val*i);
        }
    }

    idx=1;

    for(auto val:primes){
        if(val>n) break;
        if(t[val].size()==0) continue;

        while(t[val].size()){

            if(t[val].size()>1){
                if(idx>n) break;
                a[idx]=t[val].back();
                t[val].pop_back();
                idx++;

                if(idx>n) break;
                a[idx]=t[val].back();
                t[val].pop_back();
                idx++;
                if(t[val].size()>1) idx++;
            }
            else{
                if(idx>n) break;
                a[idx]=t[val].back();
                idx++;
                t[val].pop_back();
            }

        }
    }

    st.clear();
    for(int i=1;i<=n;i++){
        if(a[i]) st[a[i]]=1;
    }

    vector<int> b;
    for(int i=1;i<=n;i++){
        if(!st[i]) b.push_back(i);
    }

    for(int i=1;i<=n;i++){
        if(a[i]==0){
            a[i]=b.back();
            b.pop_back();
        }
    }

    for(int i=1;i<=n;i++) cout<<a[i]<<" ";

    cout<<endl;
}


signed main(){

	ios::sync_with_stdio(0);
	cin.tie(0);

    init();

	int t=1;
	cin>>t; 
	
	while(t--){
		solve(); 
	}

}

G. Sakura Adachi and Optimal Sequences

首先,翻倍的操作一定优于单点 \(+1\) 的操作,所以一定要最大化翻倍操作的数量

假设翻倍操作的数量是 \(m\)

\(m\) 是满足所有 \(a[i] * 2^m <= b[i]\) 的最大值

确定 \(m\) 后,则尽可能让 \(+1\) 早进行,因为在 \(m\) 次操作前 \(+1\),相当于在 \(m\) 次操作后 \(+~2^m\)

所以从 \(b[i]\)\(a[i]\) 推,如果 \(b[i]\) 是奇数,则不得不进行一次 \(-1\) 操作,否则进行除二操作

至此,可以处理出,\(m\) 次翻倍操作中,每次翻倍操作中间需要 \(cnt[j]\)\(+1\) 操作

还是考虑操作 \(b[i]\),处理完 m 次翻倍后,设此时 \(lft[i]=b[i]-a[i]\)

所以在初始时还需要进行 \(lft[1-n]\)\(+1\) 操作

此时操作次数是固定的,组合数学统计方案数即可

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 1e6+3;

vector<int> fact(mod+3);

int qmi(int a,int b,int p){
    int res=1;
    while(b){
        if(b&1) res=res*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return res;
}

void init(){
    int mx=1e6+3;
    fact[0]=fact[1]=1;
    for(int i=2;i<=mx;i++){
        fact[i]=fact[i-1]*i%mod;
    }
}

void solve(){
	int n;
    cin>>n;

    vector<int> a(n+1),b(n+1);
    int m=inf;

    for(int i=1;i<=n;i++){
        cin>>a[i];
    }

    for(int i=1;i<=n;i++){
        cin>>b[i];
        m=min(m,__lg(b[i]/a[i]));
    }

    vector<int> cnt(m+1);
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            if(b[j]&1) cnt[i]++;
            b[j]/=2; 
        }
    }

    vector<int> lft(n+1);
    for(int i=1;i<=n;i++){
        lft[i]=b[i]-a[i];
    }

    int ans1=m;
    for(int i=1;i<=n;i++){
        ans1+=lft[i];
    }
    for(int i=1;i<=m;i++){
        ans1+=cnt[i];
    }

    int ans2=1;
    for(int i=1;i<=m;i++){
        ans2*=fact[cnt[i]];
        ans2%=mod;
    }

    int sum=accumulate(lft.begin()+1,lft.end(),0ll);
    if(sum>=mod) ans2=0;
    else ans2*=fact[sum];

    ans2%=mod;

    for(int i=1;i<=n;i++){
        ans2*=qmi(fact[lft[i]],mod-2,mod);
        ans2%=mod;
    }

    cout<<ans1<<" "<<ans2<<endl;
}

signed main(){

	ios::sync_with_stdio(0);
	cin.tie(0);

    init();

	int t=1;
	cin>>t; 
	
	while(t--){
		solve(); 
	}

}
posted @ 2025-12-03 20:10  LYET  阅读(20)  评论(0)    收藏  举报