牛客挑战赛59

木桩:
链接:https://ac.nowcoder.com/acm/contest/11199/A

分析:首先考虑一个小木桩前有x个大木桩 后有y个大木桩

则这个小木桩的贡献就是x×y-x 很明显均值不等式得到x和y尽量均分才能答案最大

如果a为偶数那么恰好前后各一半

如果a为奇数那么多的那一个放在后面一定最优

code:

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
int T;  
void solve();
int main(){
	cin>>T;
	while(T--)solve();
     return 0;
}
void solve(){
	ll a,b;
	scanf("%lld%lld",&a,&b);
	ll t1=a/2;
	ll t2=t1;
	if(a%2)t2++;
	cout<<b*(t2-1)*t1<<endl;
}

游戏:
链接:https://ac.nowcoder.com/acm/contest/11199/B

分析:

假设第i个人获胜

因为要求每一个人的获胜概率

所以首先要求出直到前i-1轮是 剪刀/石头/步 获胜的概率(谁获胜的不重要 重要的是三者中哪个在前一轮胜出)

这个直接转移就好了

接下来几轮就只能第i个人获胜 所以这样倒着转移就好了

总结一下 本题的核心在与 前i-1轮是谁输赢不重要 只用关注是石头/剪刀/步 在第i-1轮胜出 后面几轮第i个人都必须赢

code:

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int mod=998244353;
const int maxn=1e5+7;
ll dp[maxn][3],f[3],ans[maxn],t[3],ni[maxn];
int n;
int a[maxn][3],cnt[maxn];
ll ksm(ll aa,ll bb){
	ll res=1;
	while(bb){
		if(bb&1)res=res*aa%mod;
		bb>>=1;
		aa=aa*aa%mod;
	}
	return res;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		int tot=0;
		for(int j=0;j<3;j++){
			scanf("%1d",&a[i][j]);
		   if(a[i][j]==1)tot++;
		}
		cnt[i]=tot;
	}
	
	for(int i=1;i<=n;i++)ni[i]=ksm(cnt[i],mod-2);
	
	for(int i=0;i<3;i++)
	if(a[1][i]==1)
	dp[1][i]=ni[1];
	
	for(int i=2;i<=n;i++)
		for(int j=0;j<3;j++)
			dp[i][j]=(dp[i-1][j]*(a[i][j]+a[i][(j+1)%3])%mod+dp[i-1][(j+1)%3]*a[i][j])%mod*ni[i]%mod;
	
	for(int i=0;i<3;i++)
	if(a[n][i]==1)
	t[i]=(t[i]+ni[n])%mod,t[(i-1+3)%3]=(t[(i-1+3)%3]+ni[n])%mod;
	for(int i=0;i<3;i++)
	f[i]=t[i];
	
	ll tt=0;
	for(int i=0;i<3;i++)
	if(a[n][i]==1)
	tt=(tt+dp[n-1][(i+1)%3]*ni[n]%mod)%mod;
	ans[n]=tt;
	
	for(int i=0;i<3;i++)
	dp[0][i]=1;
	
	for(int i=n-1;i>=1;i--){
		ll tt=0;
		for(int j=0;j<3;j++)
		if(a[i][j]==1)
		tt=(tt+dp[i-1][(j+1)%3]*ni[i]%mod*f[j]%mod)%mod;
		t[0]=t[1]=t[2]=0;
		for(int j=0;j<3;j++)
			if(a[i][j]==1)
			t[j]=(t[j]+ni[i])%mod,t[(j-1+3)%3]=(t[(j-1+3)%3]+ni[i])%mod;
		for(int j=0;j<3;j++)
		f[j]=f[j]*t[j]%mod; 
		ans[i]=tt;
	}
	for(int i=1;i<=n;i++)
	cout<<ans[i]<<" ";
     return 0;
}

异或

分析:

相较于一般的线性基多了一个奇数偶数的限制

那怎么办呢?

针对偶数 将原数组a变为b[i]=a[i]^a[i+1]

针对奇数 将原数组a变为b[i]=a[i]^(2的inf次方)

不得不说真的太巧妙了 学到了

还有就是要用到bitset 用法我以前有写过https://zhuanlan.zhihu.com/p/578274936

#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) x&(-x)
using namespace std;
const int maxn=2005;
bitset<maxn>a[maxn],b[maxn],x[maxn],p[maxn],ans,mm;
int n;
void insert(bitset<maxn>t){
	for(int i=maxn-1;i>=0;i--){
		if((t>>i)==0)continue;
		if(!p[i].count()){p[i]=t;break;}
		else t^=p[i];
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)cin>>x[i];
	for(int i=1;i<n;i++)insert(x[i]^x[i+1]);
	insert(x[n]^x[1]);
	for(int i=maxn-1;i>=0;i--)
	if(!ans[i])ans^=p[i];
	int pos=maxn-1;
	while(!ans[pos]&&pos)pos--;
	while(pos>=0)cout<<ans[pos--];
	cout<<endl;
	
	ans.reset();mm.set(maxn-1);
	for(int i=0;i<maxn;i++)p[i].reset();
	for(int i=1;i<=n;i++)insert(x[i]^mm);
	for(int i=maxn-1;i>=0;i--)
	if(!ans[i])ans^=p[i];
	pos=maxn-2;
	while(!ans[pos]&&pos)pos--;
	while(pos>=0)cout<<ans[pos--];
	cout<<endl;
	return 0;
}
posted @ 2022-07-13 11:28  wzx_believer  阅读(38)  评论(0)    收藏  举报