Codeforces Round 976 (Div. 2) 題解(A-E)

mj666發表於2024-10-13

Codeforces Round 976(Div 2) 題解 (A-E)

A

題意

給你兩個整數 \(n\)\(k\)

在一次操作中,你可以從 \(n\) 中減去 \(k\) 的任意次冪。形式上,在一個操作中,你可以用 \((n-k^x)\) 替換任何非負整數 \(x\)\(n\)

求使 \(n\) 等於 \(0\) 所需的最小運算次數。

Solution

\(n\) 轉為 \(k\) 進位制,答案即為每位的數的和。時間複雜度 \(O(\sum logn)\)

#include <bits/stdc++.h>
#define LL long long
#define mod 1000000007
#define lowbit(x) (x&(-x))
void write(LL x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10+48);
}
LL read(){
	LL x=0,f=1;char ch=getchar();
	while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
	return x*f;
}
using namespace std;
const int N=60;
int n,k,a[N],cnt;
void solve(){
	n=read(),k=read(),cnt=0;
	if(k==1){
		write(n),puts("");
		return;
	}
	while(n){
		a[++cnt]=n%k;
		n/=k;
	}
	LL ans=0;
	for(int i=1;i<=cnt;++i){
		ans+=a[i];
	}
	write(ans),puts("");
}
int main(){
	int T=read();
	while(T--){
		solve();
	}
	return 0;
}

B

題意

假設你有編號為 \(1, 2, \ldots, n\)\(n\) 燈泡。最初,所有的燈泡都是亮著的。翻轉燈泡的狀態意味著如果它以前是開著的,就把它關掉,否則就把它開啟。

接下來,執行以下操作:

  • 對於每個 \(i = 1, 2, \ldots, n\) ,翻轉所有 \(j\) 的燈泡狀態,使 \(j\) 能被 \(i^\dagger\) 整除。

在完成所有操作後,將有幾個燈泡仍然亮著。您的目標是使這個數字恰好為 \(k\)

找到最小的合適的 \(n\) ,使得在執行操作後恰好有 \(k\) 個燈泡亮著。我們可以證明一個答案總是存在的。

\(^\dagger\) 一個整數 \(x\) 能被 \(y\) 整除,如果存在一個整數 \(z\) 能被 \(x = y\cdot z\) 整除。

Solution

\(i\) 個燈會被操作 \(i\) 的因數個數次。第 \(i\) 個燈操作之後仍是亮著的,當且僅當 \(i\) 是完全平方數。二分即可。

時間複雜度 \(O(TlogV)\)

#include <bits/stdc++.h>
#define LL long long
#define mod 1000000007
#define lowbit(x) (x&(-x))
void write(LL x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10+48);
}
LL read(){
	LL x=0,f=1;char ch=getchar();
	while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
	return x*f;
}
using namespace std;
LL k;
void solve(){
	k=read();
	LL L=2,R=2e18,res;
	auto chk=[&](LL x)->bool{
		return x-(LL)sqrtl(x)>=k;
	};
	while(L<=R){
		LL mid=L+R>>1;
		if(chk(mid)) R=mid-1,res=mid;
		else L=mid+1;
	}
	write(res),puts("");
}
int main(){
	int T=read();
	while(T--) solve();
	return 0;
}

C

題意

給定三個非負整數 \(b\)\(c\)\(d\)

請找到一個非負整數 \(a \in [0, 2^{61}]\) ,使得 \((a | b)-(a \& c)=d\) ,其中 \(|\)\(\&\) 分別表示位或操作位與操作

如果存在 \(a\) ,則列印其值。如果沒有解,則列印單個整數 \(-1\) 。如果有多個解決方案,列印其中任何一個。

Solution

\(a,b,c\) 轉為二進位制,分類討論每一位上的情況。時間複雜度 \(O(TlogV)\)

#include <bits/stdc++.h>
#define LL long long
#define mod 1000000007
#define lowbit(x) (x&(-x))
void write(LL x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10+48);
}
LL read(){
	LL x=0,f=1;char ch=getchar();
	while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
	return x*f;
}
using namespace std;
const int N=65;
LL a;
void solve(){
	LL x=read(),y=read(),z=read();
	auto cal=[&](LL x)->vector<int>{
		vector<int> ans(N);
		int cnt=0;
		while(x){
			ans[++cnt]=x%2;
			x>>=1;
		}
		return ans;
	};
	vector<int> b=cal(x);
	vector<int> c=cal(y);
	vector<int> d=cal(z);
	for(int i=64;i>=1;--i){
		LL opt;
		if(d[i]==0){
			if(b[i]==0 && c[i]==0) opt=0;
			else if(b[i]==1 && c[i]==1) opt=1;
			else if(b[i]==0 && c[i]==1) opt=0;
			else{
				puts("-1");
				return;
			}
		}
		else{
			if(b[i]==0 && c[i]==0) opt=1;
			else if(b[i]==1 && c[i]==1) opt=0;
			else if(b[i]==1 && c[i]==0) opt=1;
			else{
				puts("-1");
				return;
			}
		}
		a=(a<<1)+opt;
	}
	write(a),puts("");
}
int main(){
	int T=read();
	while(T--) solve();
	return 0;
}

D

題意

一個晴朗的晚上,愛麗絲坐下來玩經典的遊戲“串連點”,但有一個轉折。

為了玩這個遊戲,愛麗絲畫了一條直線,並在上面標記了 \(n\) 點,索引從 \(1\)\(n\) 。最初,點之間沒有弧,所以它們都是不相交的。之後,Alice執行如下型別的 \(m\) 操作:

  • 她選擇了三個整數 \(a_i\)\(d_ i\) ( \(1 \le d _ i \le 10\) )和 \(k _ i\)
  • 她選擇點 ​\(a _ i, a _ i+d _ i, a _ {i}+2d_ i, a _ i+3d _ i, \ldots, a _ i+k _ i\cdot d _ i\) 並將這些點的每一對用弧連線起來。

在完成所有 \(m\) 操作後,她想知道這些點形成的 \(\dagger\) 連線元件的個數。請幫她找到這個號碼。

\(\dagger\) 如果兩點之間有一條透過若干(可能為零)弧線和其他點的路徑,則稱兩點在一個連通分量中。

Solution

注意到 \(d_i\) 很小,因此對於一個點,它只可能被它前面的 \(10\) 個點內的點連線,用並查集維護。時間複雜度 \(O(\sum nlogn)\)

#include <bits/stdc++.h>
#define LL long long
#define mod 1000000007
#define lowbit(x) (x&(-x))
void write(LL x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10+48);
}
LL read(){
	LL x=0,f=1;char ch=getchar();
	while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
	return x*f;
}
using namespace std;
const int N=2e5+5;
int n,m,a,d,p,cnt[N][11],fa[N];
int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
void solve(){
	n=read(),m=read();
	for(int i=1;i<=n;++i){
		fa[i]=i;
	}
	for(int i=1;i<=m;++i){
		a=read(),d=read(),p=read();
		cnt[a][d]=max(cnt[a][d],p);
	}
	auto merge=[&](int x,int y)->void{
		x=find(x),y=find(y);
		if(x==y) return;
		fa[x]=y;
	};
	for(int i=1;i<=n;++i){
		for(int j=max(1,i-10);j<i;++j){
			int k=i-j;
			if(!cnt[j][k]) continue;
			cnt[i][k]=max(cnt[i][k],cnt[j][k]-1);
			merge(i,j);
		}
	}
	int ans=0;
	for(int i=1;i<=n;++i){
		if(find(i)==i) ans++;
	}
	write(ans),puts("");
	for(int i=1;i<=n;++i){
		for(int j=1;j<=10;++j){
			cnt[i][j]=0;
		}
	}
}
int main(){
	int T=read();
	while(T--) solve();
	return 0;
}

E

Solution

考慮 \(dp_{i,j}\) 表示前 \(i\) 個數能構成的集合且其中元素的異或和為 \(j\) 能發生的機率。

\[dp_{i+1,j\oplus a_{i+1}}+=dp_{i,j}\times \dfrac{p_i}{10000} \\ dp_{i+1,j}+=dp_{i,j}\times \dfrac{10000-p_i}{10000} \]

答案為

\[\sum _{i=0}^{1023}dp_{n,i}\times i^2 \]

時間複雜度 \(O(\sum 1024n)\)

小心寫得不好導致爆long long;多測記得清空。

#include <bits/stdc++.h>
#define LL long long
#define mod 1000000007
#define lowbit(x) (x&(-x))
void write(LL x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10+48);
}
LL read(){
	LL x=0,f=1;char ch=getchar();
	while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
	return x*f;
}
using namespace std;
const int N=2e5+5;
LL n,a[N],p[N],inv,dp[2][1050];
LL qpow(LL x,LL power){
	LL ans=1;
	x%=mod;
	while(power){
		if(power&1) ans=ans*x%mod;
		power>>=1;
		x=x*x%mod;
	}
	return ans;
}
void solve(){
	n=read();
	for(int i=1;i<=n;++i){
		a[i]=read();
	}
	inv=qpow(10000,mod-2);
	for(int i=1;i<=n;++i){
		p[i]=read()*inv%mod;
	}
	memset(dp,0,sizeof(dp));
	dp[1][a[1]]=p[1];
	dp[1][0]=(1-p[1]+mod)%mod;
	for(int i=1;i<n;++i){
		for(int j=0;j<1024;++j){
			dp[(i+1)&1][j^a[i+1]]=(dp[(i+1)&1][j^a[i+1]]+1ll*dp[i&1][j]*p[i+1]%mod)%mod;
			dp[(i+1)&1][j]=(dp[(i+1)&1][j]+1ll*dp[i&1][j]*(1-p[i+1]+mod)%mod)%mod;
		}
		for(int j=0;j<1024;++j) dp[i&1][j]=0;
	}
	LL ans=0;
	for(int i=0;i<1024;++i){
		ans=(ans+1ll*dp[n&1][i]*i%mod*i%mod)%mod;
	}
	write(ans),puts("");
}
int main(){
	int T=read();
	while(T--) solve();
	return 0;
}

相關文章