链接
单位根反演
其实就是一个公式,学过 的人都能很容易的理解:
证明很简单,当
时
,所以
,那么右边就等于
否则,就是一个等比数列求和,
,右边等于
题解
根据 ,以及异或运算的性质,可以得到以下结论:
当 为奇数的时候,
当 为偶数的时候,
其中 表示异或
所以现在需要解决的问题就是对于某个给定的 ,求出
直接硬写:
令
所以直接枚举 然后快速幂就行了
代码
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 1500000
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
#define mod 998244353ll
ll n, k, wk[maxn];
ll fastpow(ll a, ll b)
{
ll t(a%mod), ans(1);
b=(b%(mod-1)+(mod-1))%(mod-1);
for(;b;b>>=1,t=t*t%mod)if(b&1)(ans*=t)%=mod;
return ans;
}
void pre()
{
ll i;
wk[0]=1, wk[1]=fastpow(3,(mod-1)/k);
rep(i,2,k-1)wk[i]=wk[i-1]*wk[1]%mod;
}
ll calc(ll t)
{
ll i, j, ans=0, mi=1, wkt=fastpow(wk[1],-t);
rep(j,0,k-1)
{
ll tmp=mi*fastpow(1+wk[j],n)%mod;
(ans+=tmp)%=mod;
mi=mi*wkt%mod;
}
ans=ans*fastpow(k,mod-2)%mod;
return (ans+mod)%mod;
}
char s[maxn];
ll tmp[maxn];
int main()
{
ll i, j, len, t1=0, t2;
scanf("%s%lld",s,&k); len=strlen(s);
rep(i,0,len-1)(n=n*10+s[i]-0x30)%=(mod-1);
if(s[len-1]%2==1){printf("0"); return 0;}
if(k==1){printf("%lld",fastpow(2,n)); return 0;}
rep(i,0,len-1)tmp[i]=s[i]-0x30;
rep(i,0,len-1)
{
tmp[i+1]+=tmp[i]%2*10;
tmp[i]/=2;
t1=(t1*10+tmp[i])%k;
}
t2=(t1+k/2)%k;
pre();
printf("%lld",calc(t1)^calc(t2));
return 0;
}