省选模拟29

A. 卷王

\(f_{sta}\) 表示将 \(sta\) 这个状态全部变成 \(0\) 所需要的最短时间

枚举时间从小到大依次转移,再对每种长度的串都跑一次

考试的时候傻了,只倒着从 \(S\) 转移到 \(0\) 了,没想到从 \(0\) 开始去转移

Code
#include<bits/stdc++.h>
//#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
	int 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<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int T,n,S,U;
int a[20],inc[20];
int f[20][65536];
char st[20];
inline void solve(){
	scanf("%s",st+1);n=strlen(st+1);S=0;U=(1<<(n+1))-1;
	memset(a,0,sizeof(a));for(int i=1;i<=n;i++) a[i]=st[i]-'0';
	for(int i=1;i<=n;i++) S|=(a[i]<<(i-1));
	printf("%d\n",f[n][S]);
}
inline void pre(int len){
	f[len][0]=0;U=(1<<len)-1;
	for(int l=1;l<=len;l++){
		for(int sta=0,vsta;sta<=U;sta++) if(f[len][sta]<l){
			for(int j=0;j<len;j++){
				vsta=sta^(inc[l-1]<<j);vsta&=inc[len-1];
				f[len][vsta]=min(f[len][vsta],l);
			}
		}
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("roll.in","r",stdin);
	freopen("roll.out","w",stdout);
	inc[0]=1;for(int i=1;i<=16;i++) inc[i]=inc[i-1]<<1|1;
	memset(f,0x3f,sizeof(f));
	for(int i=1;i<=16;i++) pre(i);
	T=read();while(T--) solve();
	return 0;
}

B. 赢王

考虑如何计算合法区间的贡献

因为每个数都是 \(k\) 的倍数,所以每个前缀也都是 \(k\) 的倍数

而第一个只能从第二个转移,设他为 \(x\) ,那么要么他全都给出去变成 \(0\) ,要么从旁边拿 \(k-x\) 变成倍数

所以他的贡献就是 \(\min(x,k-x)\)

再看第二个位置,左边的是 \(k\) 的倍数了,于是也只能从右边转移,以此类推

每个位置的贡献都是这一段的前缀和 \(x\)\(k-x\)\(\min\) 的结果

区间合法当且仅当区间和为 \(k\) 的倍数

\([a,b],[b+1,c]\) 都合法,那么 \([a,c]\) 也合法且答案为两个区间的答案的加和

所以只考虑相邻端点之间的区间然后再用他乘上一个系数,这样就有 \(O(n)\) 个区间

每个区间的答案就是 \(\sum\limits_{i=l}^rg(sum_i-sum_{l-1})\)\(g(x)\) 表示 \(\min(x,k-x)\)

计算答案可以用主席树,然后再分类讨论计算

Code
#include<bits/stdc++.h>
//#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define lson st[x].ls
#define rson st[x].rs
#define mod 998244353
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int 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<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,k,ans;
int a[1000010],sum[1000010];
int lc[1000010],rc[1000010];
int rt[1000010],tot;
int O[1000010],b[1000010],cnt;
map<int,int>mp;
pair<int,int> tmp;
vector<int>vec[1000010];
struct seg{int ls,rs,sum,num;}st[1000010*30];
void ins(int &x,int l,int r,int pos){
	int pre=x;x=++tot;st[x]=st[pre];st[x].num++;(st[x].sum+=pos)%=mod;
	if(l==r) return ;
	int mid=(l+r)>>1;
	if(pos<=mid) ins(lson,l,mid,pos);
	else ins(rson,mid+1,r,pos);
}
pair<int,int> query(int u,int v,int l,int r,int L,int R){
	if(!u&&!v) return make_pair(0,0);
	if(L<=l&&r<=R) return make_pair((st[u].sum-st[v].sum+mod)%mod,st[u].num-st[v].num);
	int mid=(l+r)>>1;pair<int,int> res,t;res.first=res.second=0;
	if(L<=mid) t=query(st[u].ls,st[v].ls,l,mid,L,R),(res.first+=t.first)%=mod,res.second+=t.second;
	if(R>mid) t=query(st[u].rs,st[v].rs,mid+1,r,L,R),(res.first+=t.first)%=mod,res.second+=t.second;
	return res;
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("win.in","r",stdin);
	freopen("win.out","w",stdout);
	n=read(),k=read();for(int i=1;i<=n;i++) a[i]=read();ans=mod-1ll*(n+1)*n/2%mod;
	for(int i=1;i<=n;i++) sum[i]=(sum[i-1]+a[i])%k;
	for(int i=1;i<=n;i++) O[i]=b[i]=sum[i];O[n+1]=0;sort(O+1,O+1+1+n);cnt=unique(O+1,O+1+1+n)-O-1;
	for(int i=1;i<=n;i++) b[i]=lower_bound(O+1,O+1+cnt,b[i])-O;
	vec[1].emplace_back(0);for(int i=1;i<=n;i++) vec[b[i]].emplace_back(i);
	for(int i=1;i<=cnt;i++) (ans+=1ll*vec[i].size()*(vec[i].size()-1)/2%mod)%=mod;
	for(int i=1;i<=n;i++) ins(rt[i]=rt[i-1],0,k-1,sum[i]);
	for(int i=1,l,r,L,R,resk,res;i<=cnt;i++) for(int j=1;j<vec[i].size();j++){
		l=vec[i][j-1]+1,r=vec[i][j];resk=k/2;L=sum[l-1];res=0;
		if(L+resk<=k-1){
			R=L+resk;resk=0;tmp=query(rt[r],rt[l-1],0,k-1,L,R);(res+=(tmp.first-1ll*tmp.second*sum[l-1]%mod+mod)%mod)%=mod;
			L=R+1;R=k-1;tmp=query(rt[r],rt[l-1],0,k-1,L,R);(res+=(1ll*k*tmp.second%mod-(tmp.first-1ll*tmp.second*sum[l-1]%mod+mod)%mod+mod)%mod)%=mod;
			L=0;R=sum[l-1]-1;tmp=query(rt[r],rt[l-1],0,k-1,L,R);(res+=(1ll*k*tmp.second%mod-(tmp.first+1ll*tmp.second*(k-sum[l-1])%mod+mod)%mod+mod)%mod)%=mod;
		}else{
			R=k-1;resk-=R-L+1;tmp=query(rt[r],rt[l-1],0,k-1,L,R);(res+=(tmp.first-1ll*tmp.second*sum[l-1]%mod+mod)%mod)%=mod;
			L=0;R=resk;tmp=query(rt[r],rt[l-1],0,k-1,L,R);(res+=(1ll*tmp.second*k%mod+tmp.first-1ll*tmp.second*sum[l-1]%mod+mod)%mod)%=mod;
			L=resk+1;R=sum[l-1]-1;tmp=query(rt[r],rt[l-1],0,k-1,L,R);(res+=(1ll*k*tmp.second%mod-(tmp.first+1ll*tmp.second*(k-sum[l-1])%mod+mod)%mod+mod)%mod)%=mod;
		}
		(ans+=1ll*res*j%mod*(vec[i].size()-j)%mod)%=mod;
	}
	printf("%d\n",ans);
	return 0;
}

C. 稳王

题解很详细,于是就直接当复读机了

最优策略是能干掉时用 \(1\) 回合直接干掉,否则不出牌

期望回合数可以转化成 \(1+\) 第一回合没结束的概率 \(+\) 第二回合没结束的概率 \(+...\)

又可以转化为不能打赢的拿牌序列的概率和 \(+1\)

于是考虑每种拿牌组合

1.只有复读, \(\sum\limits_{i=1}^{\infty}\frac{1}{3^i}=\frac{1}{2}\)

2.只有毒药, \(n\) 回合内赢不了 \(\sum\limits_{i=1}^n\frac{1}{3^i}=\frac{1-\frac{1}{3^n}}{2}\)

3.只有火球, 设 \(m=\left \lfloor \frac{n-1}{2} \right \rfloor\) 那么 \(m\) 回合内赢不了 \(\sum\limits_{i=1}^m\frac{1}{3^i}=\frac{1-\frac{1}{3^m}}{2}\)

4.复读和火球,复读可以变成火球,于是和 \(3\) 类似 \(\sum\limits_{i=1}^m\frac{2^i-2}{3^i}=2(1-(\frac{2}{3})^m)-(1-\frac{1}{3^m})\)

5.复读和毒药,毒药伤害为 \(1\) ( 第一张没伤害 ),复读伤害为 \(2\) ,那么可以用 \(dp\) 去求,发现可以用矩阵去优化,为了方便转移可以让第一张有伤害,然后再让总体的伤害 \(+1\) ,设 \(f_{i,0/1,0/1}\) 表示造成 \(i\) 点伤害,是否有复读,是否有毒药,那么要求的就是 \(\sum\limits_{i=1}^nf_{i,1,1}\)

6.复读和火球,\(dp\) 类似 \(5\)

7.都有,\(dp\) 类似 \(5\)

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define mod 998244353
#define i2 499122177
#define i3 332748118
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int 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<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int T,n,m,res;
int id[10][10][10],tot;
int idd[10][10][10][10];
struct mat{
	int a[40][40];
	inline mat operator*(const mat &b)const{
		mat c;memset(c.a,0,sizeof(c,a));
		for(int i=0;i<=32;i++) for(int k=0;k<=32;k++) if(a[i][k]) for(int j=0;j<=32;j++) (c.a[i][j]+=a[i][k]*b.a[k][j])%=mod;
		return c;
	}
}tmp,k5[65],k6[65],k7[65];
inline int qpow(int x,int k){
	int res=1,base=x;
	while(k){if(k&1) res=res*base%mod;base=base*base%mod;k>>=1;}
	return res;
}
inline int K5(int n){
	memset(tmp.a,0,sizeof(tmp.a));n++;tmp.a[0][1]=1;
	for(int i=0;i<=60;i++) if((n>>i)&1) tmp=tmp*k5[i];
	return tmp.a[0][0];
}
inline int K6(int n){
	memset(tmp.a,0,sizeof(tmp.a));n++;tmp.a[0][1]=1;
	for(int i=0;i<=60;i++) if((n>>i)&1) tmp=tmp*k6[i];
	return tmp.a[0][0];
}
inline int K7(int n){
	memset(tmp.a,0,sizeof(tmp.a));n++;tmp.a[0][1]=1;
	for(int i=0;i<=60;i++) if((n>>i)&1) tmp=tmp*k7[i];
	return tmp.a[0][0];
}
inline void solve(){
	n=read();m=(n-1)/2;res=1;
	(res+=i2)%=mod;
	(res+=(1-qpow(i3,n)+mod)%mod*i2%mod)%=mod;
	(res+=(1-qpow(i3,m)+mod)%mod*i2%mod)%=mod;
	(res+=2*(1-qpow(2*i3%mod,m)+mod)%mod-(1-qpow(i3,m)+mod)%mod+mod)%=mod;
	(res+=K5(n))%=mod;
	(res+=K6(n))%=mod;
	(res+=K7(n))%=mod;
	printf("%lld\n",res);
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("stable.in","r",stdin);
	freopen("stable.out","w",stdout);
	memset(tmp.a,0,sizeof(tmp.a));tot=0;
	for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) id[i][j][k]=++tot;
	for(int i=1;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) tmp.a[id[i-1][j][k]][id[i][j][k]]=1;
	tmp.a[0][0]=1;tmp.a[id[0][1][1]][0]=1;
	tmp.a[id[0][0][0]][id[0][0][1]]=i3;tmp.a[id[0][0][1]][id[0][0][1]]=i3;
	tmp.a[id[0][1][0]][id[0][1][1]]=i3;tmp.a[id[0][1][1]][id[0][1][1]]=i3;
	tmp.a[id[1][0][0]][id[0][1][0]]=i3;tmp.a[id[1][1][0]][id[0][1][0]]=i3;
	tmp.a[id[1][0][1]][id[0][1][1]]=i3;tmp.a[id[1][1][1]][id[0][1][1]]=i3;
	k5[0]=tmp;for(int i=1;i<=60;i++) k5[i]=k5[i-1]*k5[i-1];
	
	memset(tmp.a,0,sizeof(tmp.a));tot=0;
	for(int i=0;i<3;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) id[i][j][k]=++tot;
	for(int i=1;i<3;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) tmp.a[id[i-1][j][k]][id[i][j][k]]=1;
	tmp.a[0][0]=1;tmp.a[id[0][1][1]][0]=1;
	tmp.a[id[0][0][0]][id[0][0][1]]=i3;tmp.a[id[0][0][1]][id[0][0][1]]=i3;
	tmp.a[id[0][1][0]][id[0][1][1]]=i3;tmp.a[id[0][1][1]][id[0][1][1]]=i3;
	tmp.a[id[2][0][0]][id[0][1][0]]=i3;tmp.a[id[2][1][0]][id[0][1][0]]=i3;
	tmp.a[id[2][0][1]][id[0][1][1]]=i3;tmp.a[id[2][1][1]][id[0][1][1]]=i3;
	k6[0]=tmp;for(int i=1;i<=60;i++) k6[i]=k6[i-1]*k6[i-1];
	
	memset(tmp.a,0,sizeof(tmp.a));tot=0;
	for(int i=0;i<4;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) for(int l=0;l<2;l++) idd[i][j][k][l]=++tot;
	for(int i=1;i<4;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) for(int l=0;l<2;l++) tmp.a[idd[i-1][j][k][l]][idd[i][j][k][l]]=1;
	tmp.a[0][0]=1;tmp.a[idd[0][1][1][1]][0]=1;
	for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) tmp.a[idd[0][i][j][k]][idd[0][i][j][k|1]]=i3;
	for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) tmp.a[idd[2][i][j][k]][idd[0][i][j|1][k]]=i3;
	for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) tmp.a[idd[3][i][j][k]][idd[0][i|1][j][k]]=i3;
	k7[0]=tmp;for(int i=1;i<=60;i++) k7[i]=k7[i-1]*k7[i-1];
	
	T=read();while(T--) solve();
	return 0;
}
posted @ 2022-03-11 19:49  Max_QAQ  阅读(69)  评论(0编辑  收藏  举报