OpenJ_POJ 1058 Guideposts

Problem

OpenJ_POJ

Solution

如果我们用 \(G\) 来表示邻接矩阵,那么答案其实就是求\(\sum_{k|i}^n \binom n i G^i\)

为了消除整除的限制,我们可以考虑单位根反演:

\[\frac 1 k\sum_{i=0}^{k-1}w_k^{in}=[k|n] \]

那么原题就是要求

\[\frac 1 k\sum_{i=0}^n \binom n i G^i\sum_{j=0}^{k-1}w_k^{ij} \]

\[\frac 1 k\sum_{j=0}^{k-1}\sum_{i=0}^n \binom n i (Gw_k^j)^i \]

\[\frac 1 k\sum_{j=0}^{k-1}(Gw_k^j+1)^n \]

注意到题目的一个限制\(P\equiv 1 \pmod k\),此时有\(w_k=g^{\frac {p-1} {k}}\)。为什么呢?因为\(w_k^k=1=g^{p-1}\),而且显然根据原根的性质,\(\forall_{i<k} w_k^i\)都两两不相等。

时间复杂度\(O(km^3\log n)\)

Code

#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
int m,k,l,s,t,cnt,mod,G,wk,ans,pri[40];
ll n;
int pls(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
struct Matrix{
	int a[5][5];
	Matrix(){memset(a,0,sizeof(a));}
	int* operator [] (int x){return a[x];}
	void clear(){memset(a,0,sizeof(a));}
	Matrix operator * (Matrix &b)const
	{
		Matrix res;
		for(int i=0;i<5;i++)
		  for(int k=0;k<5;k++)
		    for(int j=0;j<5;j++)
		      res[i][j]=pls(res[i][j],(ll)a[i][k]*b[k][j]%mod);
		return res;
	}
	Matrix operator + (Matrix b)const
	{
		Matrix res;
		for(int i=0;i<5;i++)
		  for(int j=0;j<5;j++)
		    res[i][j]=pls(a[i][j],b[i][j]);
		return res;
	}
	Matrix operator * (const int &b)const
	{
		Matrix res;
		for(int i=0;i<5;i++)
		  for(int j=0;j<5;j++)
		    res[i][j]=(ll)a[i][j]*b%mod;
		return res;
	}
}A,B,C,E;
int power(int x,int y)
{
	int res=1;
	for(;y;y>>=1,x=(ll)x*x%mod)
	  if(y&1ll)
	    res=(ll)res*x%mod;
	return res;
}
Matrix mat_pow(Matrix x,ll y)
{
	Matrix res=x;
	for(--y;y;y>>=1,x=x*x)
	  if(y&1)
	    res=res*x;
	return res;
}
void find_G()
{
	int x=mod-1,f;
	for(int i=2;i*i<=x;i++)
	  if(x%i==0)
	  {
	  	pri[++cnt]=i;
	  	while(x%i==0) x/=i;
	  }
	if(x>1) pri[++cnt]=x;
	for(G=2;;G++)
	{
		f=1;
		for(int j=1;j<=cnt;j++)
		  if(power(G,(mod-1)/pri[j])==1)
		    {f=0;break;}
		if(f) return ;
	}
}
int input()
{
	int u,v;
	if(scanf("%d",&m)==EOF) return 0;
	cnt=0;A.clear();B.clear();C.clear();
	read(n);read(k);read(mod);
	read(l);read(s);read(t);--s;--t;
	for(int i=1;i<=l;i++)
	{
		read(u);read(v);
		++C[v-1][u-1];
	}
	for(int i=0;i<5;i++) E[i][i]=1;
	find_G();B[s][0]=1;
	return 1;
}
int main()
{
	while(input())
	{
		wk=power(G,(mod-1)/k);
		for(int i=0;i<k;i++,C=C*wk)
		  A=A+mat_pow(C+E,n);
		A=A*B;
		ans=(ll)A[t][0]*power(k,mod-2)%mod;
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2019-02-16 15:30  totorato  阅读(271)  评论(0编辑  收藏  举报