其他分享
首页 > 其他分享> > [atARC144F]Arithmetic Sequence Nim

[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