P1659 [国家集训队]拉拉队排练

Jisoo

manacher算法有个性质

就是求出来的\(p_i\)是以i为中心的回文串长度+1

所以manacher求出p,差分一下就行了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<stack>
#include<algorithm>
using namespace std;
#define int long long
template<class T>inline void read(T &x)
{
    x=0;register char c=getchar();register bool f=0;
    while(!isdigit(c))f^=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    if(f)x=-x;
}
template<class T>inline void print(T x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar('0'+x%10);
}
int t;
int n;
int r;
int m;
int cnt;
long long prime[10000001];
int maxn=10000005;
int vis[10000005];
int fz[10000005];
void prim(){
	for(int i=2;i<=maxn;++i){
		if(!vis[i]){
			prime[++cnt]=i;
		}
		for(int j=1;j<=cnt&&prime[j]*i<=maxn;++j){
			vis[i*prime[j]]=1;
			if(i%prime[j]==0){
				break;
			}
		}
	}
}
int qk(int bas,int m,int p){
	long long ans=1;
	while(m){
		if(m&1){
			ans=(ans*1ll*bas)%p;
		}
		bas*=bas;
		bas%=p;
		m>>=1;
	}
	return ans;
}
int fac[10000007];
int cop[10000007];
int fm[10000007];
signed main(){
	prim();
	read(t);read(r);
	fac[0]=1;
	for(int i=1;i<=maxn;++i){
		if(i!=r) fac[i]=fac[i-1]*1ll*i%r;
		else fac[i]=fac[i-1];
	}
	fz[1]=(prime[1]-1)%r;cop[1]=prime[1];
	for(int i=2;i<=cnt;++i){
			fz[i]=(fz[i-1])*1ll*(prime[i]-1)%r;
			cop[i]=prime[i];
	}
	for(int i=1;i<=cnt;++i){
		if(cop[i]!=r) cop[i]=qk(cop[i],r-2,r);
	}
	for(int i=2;i<=cnt;++i){
		if(cop[i]!=r) cop[i]=cop[i]*1ll*cop[i-1]%r;
		else cop[i]=cop[i-1]; 
	}
	while(t--){
		read(n);read(m);
		if(m<r&&r<=n){
			puts("0");
			continue;
		}
		int pl=upper_bound(prime+1,prime+1+cnt,m)-prime-1;
		if(pl<1){
			printf("%lld\n",fac[n]);
		}else{
			printf("%lld\n",fac[n]*1ll*fz[pl]%r*1ll*cop[pl]%r);
		}
	}
	return 0;
}
posted @ 2021-11-08 17:24  Simex  阅读(34)  评论(0编辑  收藏  举报