把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

ARC134E Modulo Nim

题面传送门

写了一个sb错误调了半天……

首先我们考虑如何判断一个序列是否先手必胜。方便起见,同样的数看成一个,显然有一个\(O(nA2^{A})\)的dp,但是显然过不了。

考虑挖掘一点性质。

容易发现,如果序列中全为\(1\)或全为\(2\),则先手必败。否则,若\(Mx\leq 2\),则先手必胜。

接下来考虑\(Mx>2\)的情况,若序列中有奇数,则显然可以先操作一次\(M=2\)形成先手必败局面,然后当前先手就必胜了。

类似的,考虑\(x\equiv2\pmod 4\)的情况下,直接操作一次\(M=4\)也可以形成全\(2\)的先手必败局面。

接下来考虑\(\bmod 3\)的情况,可以发现,如果\(x\equiv1\pmod 3\)\(x\equiv2\pmod 3\)存在且只存在一个,那么直接\(M=3\)可以形成先手必败局面,如果两个都存在,\((4,8)\)这种情况手动计算出先手必败,其余可以\(M=12\)转化成\((4,8)\)先手必败局面。

继续讨论过于繁琐,而仅剩的数只有\(16\)种,因此我们直接跑暴力就好啦!

时间复杂度\(O(\frac{nA2^{\frac{A}{12}}}{12})\)

code:

#include<bits/stdc++.h>
#define I inline
#define ll long long
#define db double
#define lb long db
#define N (200+5)
#define M ((1<<16)+5)
#define K (1500+5)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-5)
#define ull unsigned ll
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;map<vector<int>,int> F;
int n,m,k,La,Ne,A[N],x,y,z,Mi=1e9,Mx;ll dp[2][M],P1=1,ToT=1;
I int CK(vector<int> Id){
	if(Id.size()==1&&Id[0]<=2) return 0;if(Id.size()==2&&Id[0]==4&&Id[1]==8) return 0;for(int i:Id) if(i%12) return 1;
	if(F.count(Id)) return F[Id];//for(int i:Id) cerr<<i<<' ';cerr<<'\n';
	for(int i=5;i<=(*Id.rbegin());i++) {
		vector<int> P;P.clear();for(int j:Id) j%i&&(P.PB(j%i),0);sort(P.begin(),P.end());P.erase(unique(P.begin(),P.end()),P.end());
		if(P.size()&&!CK(P)) return F[Id]=1;
	}return F[Id]=0;
}
int main(){
	freopen("1.in","r",stdin);
	int i,j,h;scanf("%d",&n);for(i=1;i<=n;i++) scanf("%d",&A[i]),ToT=ToT*A[i]%mod,Mi=min(Mi,A[i]),Mx=max(Mx,A[i]);if(Mi==1){printf("%lld\n",Mx^1?ToT-1:0);return 0;}
	ToT-=2;for(i=1;i<=n;i++) P1=P1*((A[i]>=4)+(A[i]>=8))%mod;ToT-=P1-(Mi>=4)-(Mi>=8);Mx/=12;La=1;Ne=0;dp[0][0]=1;for(i=1;i<=n;i++){Ne^=1;La^=1;Me(dp[Ne],0);
		for(j=1;j*12<=A[i];j++) for(h=0;h<(1<<Mx);h++)dp[Ne][h|(1<<j-1)]+=dp[La][h];for(h=0;h<(1<<Mx);h++) dp[Ne][h]%=mod; 
	}for(i=1;i<(1<<Mx);i++){vector<int> Id;Id.clear();for(j=1;j<=Mx;j++) if(i>>(j-1)&1) Id.PB(j*12);!CK(Id)&&(ToT-=dp[Ne][i]); }printf("%lld\n",(ToT%mod+mod)%mod); 
}
posted @ 2022-07-15 22:33  275307894a  阅读(74)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end