nowcoder15254白兔的刁难

链接

点击跳转

单位根反演

其实就是一个公式,学过 F F T FFT FFT的人都能很容易的理解:

[ n ∣ k ] = 1 n ∑ i = 0 n − 1 ω n i k [n|k] = \frac{1}{n} \sum_{i=0}^{n-1} \omega_n^{ik} [nk]=n1i=0n1ωnik

证明很简单,当 n ∣ k n|k nk n ∣ i k n|ik nik,所以 ω n i k = ω n 0 = 1 \omega_{n}^{ik} = \omega_n^0 = 1 ωnik=ωn0=1,那么右边就等于 1 1 1
否则,就是一个等比数列求和, w n 0 − w n n k 1 − w n k = 0 \frac{w_{n}^{0}-w_n^{nk}}{1-w_n^k} = 0 1wnkwn0wnnk=0,右边等于 0 0 0

题解

根据 ( n i ) = ( n n − i ) \binom{n}{i}=\binom{n}{n-i} (in)=(nin),以及异或运算的性质,可以得到以下结论:

n n n为奇数的时候, a n s = 0 ans=0 ans=0

n n n为偶数的时候, a n s = a n s ( n / 2 m o d    k ) ∧ a n s ( ( n / 2 + k / 2 ) m o d    k ) ans = ans_{(n/2 \mod k)} \wedge ans_{ ((n/2+k/2) \mod k)} ans=ans(n/2modk)ans((n/2+k/2)modk)

其中 ∧ \wedge 表示异或

所以现在需要解决的问题就是对于某个给定的 t t t,求出 a n s t ans_t anst

直接硬写:

∑ i = − t n − t ( n i + t ) [ k ∣ i ] = ∑ i = − t n − t ( n i + t ) ∑ j = 0 k − 1 ω k i j = ∑ j = 0 k − 1 ∑ i = − t n − t ( n i + t ) ω k i j \sum_{i=-t}^{n-t} \binom{n}{i+t} [k|i] \\ = \sum_{i=-t}^{n-t} \binom{n}{i+t} \sum_{j=0}^{k-1} \omega_{k}^{ij} \\ = \sum_{j=0}^{k-1} \sum_{i=-t}^{n-t} \binom{n}{i+t} \omega_{k}^{ij} i=tnt(i+tn)[ki]=i=tnt(i+tn)j=0k1ωkij=j=0k1i=tnt(i+tn)ωkij

p = i + t p=i+t p=i+t

∑ j = 0 k − 1 ∑ p = 0 n ( n p ) ω k j ( p − t ) = ∑ j = 0 k − 1 ω k − j t ∑ p = 0 n ( n p ) ( ω k j ) p = ∑ j = 0 k − 1 ω k − j t ( 1 + ω k j ) n \sum_{j=0}^{k-1} \sum_{p=0}^n \binom{n}{p} \omega_{k}^{j(p-t)} \\ = \sum_{j=0}^{k-1} \omega_{k}^{-jt} \sum_{p=0}^n \binom{n}{p} (\omega_{k}^{j})^p \\ = \sum_{j=0}^{k-1} \omega_k^{-jt} (1+\omega_{k}^{j} )^n j=0k1p=0n(pn)ωkj(pt)=j=0k1ωkjtp=0n(pn)(ωkj)p=j=0k1ωkjt(1+ωkj)n

所以直接枚举 j j j然后快速幂就行了

代码

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值