省选模拟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;
}