[atARC144F]Arithmetic Sequence Nim
作者:互联网
记$sg(n)={\rm mex}\{sg(n-x)\mid x\in X\}$,考虑如何求$sg(n)$——
将$m,a,n$均除以$\gcd(m,a)$(其中$n$向下取整),以下假设$m,a$互素
特判$a=0(m=1)$的情况,此时$sg(n)=n$,以下假设$a\in [1,m)$
用$(i,j)$表示$im+ja$,则$sg(i,j)={\rm mex}\{sg(k,j-1)\mid k\le i\}$(注意$i,j$均可为负)
显然$sg(i,j)$关于$i$单调不降,且每次至多增加$1$(单调不降的$sg(i-1,j)$的前缀${\rm mex}$)
对$j$从小到大转移,维护$\{sg(i,j)\}$并分类讨论:
1.若序列开头不为$0$,结合单调不降的性质,转移后所有元素均为$0$
2.若序列开头为$0$,结合"至多增加$1$"的性质,转移后所有元素均增加$1$
另外,每次会在序列开头加入$\lceil\frac{-(j-1)a}{m}\rceil-\lceil\frac{-ja}{m}\rceil\in [0,1]$个$0$(转移后)
在此基础上,求出$im+ja=n$的某组解$(i,j)$,并分类讨论:
1.若$(i,j-1)$不存在(即作为加入的$0,\iff n<a$),则$sg(i,j)=0$
2.若$j-1$处未在开头加入$0$,记$j_{0}$为$<j$中第一个加入$0$的位置,则$sg(i,j)=(j-j_{0})\ mod\ 2$
3.若$j-1$处在开头加入$0$,记$j_{1}$为$<j$中第一个未加入$0$的位置,$j_{0}$为$<j_{1}$中第一个加入$0$的位置
结合分析,即$sg(i,j)=\begin{cases}i-s&i-s<j-j_{1}\\ j-j_{1}-(j_{1}-j_{0})\ mod\ 2&i-s\ge j-j_{1}\end{cases}$(其中$s=\lceil\frac{-(j-1)a}{m}\rceil-1$)
关于原问题,可以直接推公式,或利用单调性二分求出对应权值区间
时间复杂度视实现而定,最优应为$o(n+\log m)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 300005 4 #define mod 998244353 5 #define ll long long 6 #define LL __int128 7 int n,m,a,d,x,y,ans; 8 ll s,A[N],sA[N],sB[N]; 9 int exgcd(int a,int b,int &x,int &y){ 10 if (!b){x=1,y=0;return a;} 11 int d=exgcd(b,a%b,y,x);y-=a/b*x;return d; 12 } 13 ll get(ll j){ 14 return (-j*a+(j<0 ? m-1 : 0))/m; 15 } 16 ll get0(ll j){ 17 ll s=get(j); 18 return (-s*m+(s<0 ? a-1 : 0))/a; 19 } 20 ll get1(ll j){ 21 ll s=get(j)+j; 22 return ((LL)(s-1)*m+(s>0 ? m-a : 1))/(m-a); 23 } 24 ll Sg(ll n){ 25 if (!a)return n; 26 if (n<a)return 0; 27 ll i=(n%a)*x%a,j=(n-i*m)/a; 28 if (get(j-1)==get(j-2))return (j-get0(j-1)&1); 29 ll s=get(j-1)-1,j1=get1(j-1),j0=get0(j1-1); 30 return (i-s<j-j1 ? i-s : j-j1-(j1-j0&1)); 31 } 32 ll sg(ll n){ 33 m/=d,a/=d,n=Sg(n/d); 34 m*=d,a*=d;return n; 35 } 36 ll find(int i,ll s){ 37 if (sB[i]<s)return 0; 38 ll l=0,r=(A[i]-a)/m; 39 while (l<r){ 40 ll mid=(l+r+1>>1); 41 if (sg(A[i]-a-m*mid)>=s)l=mid; 42 else r=mid-1; 43 } 44 return (l+1)%mod; 45 } 46 int main(){ 47 scanf("%d%d%d",&n,&m,&a); 48 d=exgcd(m,a,x,y); 49 for(int i=1;i<=n;i++){ 50 scanf("%lld",&A[i]); 51 sA[i]=sg(A[i]),sB[i]=sg(A[i]-a),s^=sA[i]; 52 } 53 for(int i=1;i<=n;i++) 54 ans=(ans+(find(i,(sA[i]^s))-find(i,(sA[i]^s)+1)+mod))%mod; 55 printf("%d\n",ans); 56 return 0; 57 }View Code
标签:atARC144F,return,Nim,int,ll,mid,sg,Arithmetic,define 来源: https://www.cnblogs.com/PYWBKTDA/p/16508448.html