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

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;
}
posted @ 2024-10-13 15:11  mj666  阅读(72)  评论(0)    收藏  举报