【THUPC2019】令人難以忘記的題目名稱 / game(數論)

傳送門


題解:

倒着思考,什麼樣的序列必勝?首先是全0序列,然後是全等序列,然後是差分後是全等序列的。。。以此類推,必勝的序列必然滿足它的某一階差分在 %p 下是全0,且最少的差分次數就是答案。

以下將差分定義爲 Ai=AiAi+1A'_i=A_i-A_{i+1},這裏省略了下標的取模,默認 AA 是一個循環序列。

首先我們知道一個差分後是數列可以寫成 Ai=j=0t(tj)(1)jAi+jA'_i=\sum_{j=0}^t{t\choose j}(-1)^jA_{i+j}

考慮 t=pkt=p^k 的情況,用 Lucas 定理消去爲0的組合數,我們發現這個時候 Ai=AiAi+pkA'_i=A_i-A_{i+p^k}

假設 AA 能夠最終差分爲全00,次數爲 aa,則必然存在某個 pkap^k\geq a,使得差分 pkp^k 之後序列爲全0,則 Ai=0=AiAi+pkA'_i=0=A_i-A_{i+p^k},即 Ai=Ai+pkA_i=A_{i+p^k}

我們發現限制容易變成 Ai=Ai+gcd(n,pk)A_i=A_{i+\gcd(n,p^k)},那麼將 kk 變大我們發現最大隻需要考慮 pkn,pk+1np^k|n,p^{k+1}\nmid n,再往上就沒有意義了,這個時候看一下原序列是否滿足條件,滿足則有解,否則無解。

求答案就很簡單了,我們把 nn 變爲循環節長度 pkp^k,考慮進行若干次 pk1p^{k-1} 次差分,直到循環節長度變爲 pk1p^{k-1},可以證明覆雜度上界是等比數列求和爲 O(n,p)O(n,p)


代碼:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{

inline char gc(){
	static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}template<typename T>T get_integer(){
	char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;
	while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x;
}inline int gi(){return get_integer<int>();}

}using namespace IO;

using std::cerr;
using std::cout;

cs int N=3e5+7;

int n,p;

int A[N],B[N];

bool check(int t){
	for(int re i=0;i+t<n;++i)
		if(A[i]!=A[i+t])return false;
	return true;
}

void Main(){
	n=gi(),p=gi();
	for(int re i=0;i<n;++i)
		A[i]=gi()%p;
	int t=1;
	while(n%(t*p)==0)t*=p;
	if(!check(t)){
		puts("-1");
		return ;
	}int ans=0;
	while(t>1){
		n=t;t/=p;
		while(!check(t)){ans+=t;
			for(int re i=0;i<n;++i)
				B[i]=(A[i]-A[(i+t)%n]+p)%p;
			memcpy(A,B,sizeof(int)*n);
		}
	}cout<<ans+!!A[0]<<"\n";
}

inline void file(){
#ifdef zxyoi
	freopen("game.in","r",stdin);
#endif
}signed main(){file();Main();return 0;}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章