A Math Problem HihoCoder - 1259 (数位dp+推公式)

思路:先根据公式中,3f(n)和1+3f(n)互质的关系,列出等式,可以推出,f(n)是一个3进制数。

所以dp的时候按三进制展开就行。

因为模数不定,所以每次都要把模数传进去,其次对于f%k==t,考虑将其转化成(f-t)%k==0,这样就可以放dp里面记忆化。

dp[mod][re][pos]表示第pos为余数为re,模数为mod.

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=7e4+7;
typedef long long ll;
ll n;
int mod;
int flag;
ll p[100];
int a[100];
ll dp[6][70][maxn];
void init(int pos)
{
    p[0]=1;
    p[1]=3;
    for(int i=2;i<=pos;i++)
    {
        p[i]=p[i-1]*3%mod;
    }
}
int solve(ll n)
{
    int pos=0;
    while(n)
    {
        a[pos++]=n&1;
        n>>=1;
    }
    return pos;
}
ll dfs(int pos,int v,bool limit)
{
    if(pos==-1) return v==0;
    if(limit==0&&dp[flag][pos][v]!=-1) return dp[flag][pos][v];
    int up=limit?a[pos]:1;
    ll ans=0;
    for(int i=0;i<=up;i++)
    {
        ans+=dfs(pos-1,(v-i*p[pos]+mod)%mod,limit&&i==a[pos]);
    }
    if(limit==0) dp[flag][pos][v]=ans;
    return ans;
}
int main(int argc, char const *argv[])
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int T;
    cin>>T;
    memset(dp,-1,sizeof(dp));
    while(T--)
    {
        scanf("%lld%d",&n,&mod);
        if(mod==3) flag=0;
        else if(mod==5) flag=1;
        else if(mod==17) flag=2;
        else if(mod==257) flag=3;
        else flag=4;
        int pos=solve(n);
        init(pos);
        ll ans=0;
        for(int i=0;i<mod;i++)
        {
            ans^=dfs(pos-1,i,1)-(i==0);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40774175/article/details/82875473
今日推荐