牛客2025多校 R2

牛客2025多校 R2

I:

题目大意:

image-20250719170108550

void solve(){
	LL x,y;
	cin>>x>>y;
	if (x==1||y==1) cout<<-1<<endl;
	else cout<<1<<endl;
}

\(k=1,(x,y)>1\) 时,\(H(x)=H(y)=1\) 显然成立,如果存在 \(x=1\) 那么 \(H(x)=0\) ,又因为 \(x\ne y\) ,所以当且仅当 \(x,y\) 中不存在 \(1\) 时,\(k=1\) 为特解,否则无解

B:

题目大意:
image-20250719170928295

void solve(){
	int n;
	cin>>n;
	vector<LL> a(n);
	for (auto &x:a) cin>>x;
	if (n>60) cout<<"NO"<<endl;
    else{
    	for (int i=0;i<n;i++){
    		for (int j=i+1;j<n;j++){
    			if ((a[i]^a[j])<a[i]||(a[i]^a[j])<a[j]){
    				cout<<"NO"<<endl;
    				return;
    			}
    		}
    	}
    	cout<<"YES"<<endl;
    }
}

\(n>\log_2(10^{18})\) 时,显然数组中存在某一位上有重复的 \(1\) ,异或后一定比原来两个数小,那么之间输出 NO

否则,暴力枚举一下 \(n\le \log_2(10^{18})\) 的情况,时间复杂度很低

A:
题目大意:

image-20250719171313533

const LL mod= 998244353; 
 
LL ksm(LL a,LL b,LL p){
    LL res=1;
    while (b){
        if (b&1) res=res*a%p;
        a=a*a%p;
        b>>=1;
    }
    return res;
}
 
void solve(){
    int n;
    cin>>n;
    vector<int> a(n);
    for (int i=0;i<n;i++) cin>>a[i];
    int k=count(a.begin(),a.end(),-1);
    LL ans=0;
     
    if (a[0]==1) ans+=ksm(2,k,mod);
    else if (a[0]==-1) ans+=ksm(2,k-1,mod);
    
    for (int i=1;i<n;i++){
        LL sum=0;
        if (a[i-1]==0){
            if (a[i]==1) sum=ksm(2,k,mod);
            else if (a[i]==-1) sum=ksm(2,k-1,mod);
        }else if (a[i-1]==-1){
            if (a[i]==1) sum=ksm(2,k-1,mod);
            else if (a[i]==-1) sum=ksm(2,k-2,mod);
        }
        ans=(ans+sum)%mod;
    }
    cout<<ans<<endl;
}

只有出现这样的情况时被视为过了一天:\([0,1,0]\) ,在给定的数组前加上一个 \(0\) ,那么判断条件就能被简化为 \([0,1]\)

当前枚举的 \([a_{i-1},a_{i}]=[0,1]\) 时,显然其他地方的 \(-1\) 取任意值都不影响这一段对答案的贡献,所以这一段的贡献为 \(2^k\)

\([a_{i-1},a_i]=[0,-1]\) 时,只有当 \(a_i=1\) 时有贡献,其余地方的 \(-1\) 任意填,那么贡献为 \(2^{k-1}\)

同理可以推出 \([a_{i-1},a_i]=[-1,1],[-1,-1]\) 的情况,最后累加总贡献即可

F:
题目大意:

image-20250719171416086

void solve(){
    int n,t;
    cin>>n>>t;
    string a;
    cin>>a;
    
    int pre=0,suf=0;
    for (int i=0;i<a.size();i++)
        if (a[i]=='0') pre++;
        else break;
    for (int i=a.size()-1;i>=0;i--)
        if (a[i]=='0') suf++;
        else break;
        
    vector<int> x;
    x.push_back(pre+suf);  
    
    int st=0,cnt=0;
    for (int i=pre;i<a.size()-suf;i++){
        if (a[i]=='1'&&st==0){
            st=1;
            cnt=0;
        }else if (a[i]=='1'&&st==1){
            x.push_back(cnt);
            st=0;
            i--;
        }
        if (a[i]=='0'&&st==1) cnt++;
    }
    
    sort(x.begin(),x.end());
    int sum=max(0,x.back()-1-t);
    
    if (sum==0){
        cout<<0<<endl;
        return;
    }
    for (int i=0;i<x.size()-1;i++)
        sum+=max(0,x[i]-2*t);
    cout<<sum<<endl;
}

火的蔓延可以看作在环上的点向两侧扩张的情况,记录下每一段连续的 \(0\) ,这些子段构成了未着火的区域

因为我们有一次建立隔离带的机会,那么显然有贪心的想法是让拥有更多森林的部分不被点燃更多

对于一个未着火区域,在没有被建立隔离带的情况下每一时刻会损失掉 \(2t\) 的部分,如果一开始建立了隔离带,那么只会损失 \(t\) 的部分

所以对子段按照长度进行排序后,计算剩余的部分即可

L:

题目大意:

image-20250719171556150

const int N=5e5+10;
const int mod=998244353;
int e[N];
bool vis[N];
int siz[N],idx;

void dfs(int x){
	if (vis[x]==1) return;
	vis[x]=1;
	dfs(e[x]);
	siz[idx]++;
}

LL ksm(LL a,LL b,LL p){
	LL res=1;
	while (b){
		if (b&1) res=res*a%p;
		a=a*a%p;
		b>>=1;
	}
	return res;
}

void init(int n){
	for (int i=0;i<=n;i++)
		siz[i]=vis[i]=e[i]=0;
	idx=0;
}

void solve(){
	int n;
	cin>>n;
	for (int i=1;i<=n;i++)
		cin>>e[i];
	for (int i=1;i<=n;i++){
		if (!vis[i]){
			idx++;
			dfs(i);
		}
	}
	int odd=0,cnt=0;
	for (int i=1;i<=idx;i++){
		if (siz[i]%2) odd++;
		else if (siz[i]%2==0&&siz[i]!=2) cnt++;
	}
	
	if (odd!=0&&odd!=2){
		cout<<0<<endl;
		init(n);
		return;
	}
	if (odd){
		LL ans=1;
		for (int i=1;i<=idx;i++){
			if (siz[i]%2) ans=ans*siz[i]%mod;
			else if (siz[i]!=2)ans=ans*2%mod;
		}
		cout<<ans<<endl;
	}else{
		LL ans=0;
		for (int i=1;i<=idx;i++){
			if (siz[i]!=2)
				ans=(ans+1ll*siz[i]*siz[i]%mod*ksm(4,mod-2,mod)%mod*ksm(2,cnt-1,mod))%mod;
			else
				ans=(ans+ksm(2,cnt,mod))%mod;
		}
		cout<<ans<<endl;
	}
	
	init(n);
}

题目给定的序列可以构成一张图,且每个点有且仅有一个出度和一个入度,构成多个环

对这张图做一遍 DFS ,可以将搜索到的环分类为奇环和偶环,因为我们要删去两个节点,且删去后还能形成 \(\frac{n}{2}-1\) 个配对

那么奇环至多存在两个(包括自环点),当存在奇环时:

选取删去的两个点在不同的奇环(\(a,b\))上,那么存在的方案数为 \({\rm{siz}}_a\times {\rm{siz}}_b\)\({\rm{siz}}\) 表示环上点的数量),剩下的偶环每个偶环只能提供出两种方案,那么总方案数为:

\[{\rm{siz}}_a\times {\rm{siz}}_b \times \prod {\rm{siz}}_{even} \]

特别的,如果一个偶环的大小为 \(2\) ,那么只能提供一种方案

当不存在奇环时:我们只能够删去一个偶环上的两个点,且必须满足删去这两个点后剩下环上的点能够形成足够的配对

可以计算出对这样的一个偶环 \(x\) ,存在 \(\frac{{\rm{siz}}_x^2}{4}\) 种方案。对于每一个偶环我们都能够考虑删去他上面的两个点,那么总方案数为这些不同的方案相加:

\[\sum \left[\frac{{\rm{siz}}_x^2}{4} \prod{\rm{siz}}_{even}\right] \]

posted @ 2025-07-20 13:56  才瓯  阅读(8)  评论(0)    收藏  举报