LOJ6247 九个太阳

题目传送门

分析:
给出\(N\)\(K\),求:

\[\sum_{i=0}^{n}[k|i]\binom{n}{i} \]

想一下\([k|i]\)怎么表达
开始离谱的构造
找到\(k\)次单位根\(w_k=g^{\frac{p-1}{k}}\)
发现:

\[\sum_{j=0}^{k-1}w_k^{ij}=[k|i]k \]

\(k|i\)时,\(w_k^i=1\),显然成立
否则等比数列求和,\(\sum_{j=0}^{k-1}w_k^{ij}=\frac{1-w_k^{ik}}{1-w_k^i}=0\),也成立
好离谱的构造2333

开始推式子:

\[\sum_{i=0}^{n}[k|i]\binom{n}{i} \]

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

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

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

(二项式定理)
直接算,复杂度\(O(klogn)\)

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>

#define maxn 2000005
#define MOD 998244353

using namespace std;

inline long long getint()
{
	long long num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,k;

inline int ksm(int num,int k)
{
	int ret=1;
	for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
	return ret;
}

int main()
{
	n=getint()%(MOD-1),k=getint();
	int ans=0;
	int wn=ksm(3,(MOD-1)/k),w=ksm(3,(MOD-1)/k);
	for(int i=0;i<k;i++)
	{
		(ans+=ksm(w+1,n))%=MOD;
		w=1ll*w*wn%MOD;
	}
	ans=1ll*ans*ksm(k,MOD-2)%MOD;
	printf("%d\n",ans);
}

posted @ 2020-06-30 10:38  Izayoi_Doyo  阅读(189)  评论(0编辑  收藏  举报