UVALive 7271 A Math Problem 【数位dp计数】

数据问题:

这题UVA上的数据应该是有问题,没人AC,可以在hihocode上提交,http://hihocoder.com/problemset/problem/1259?sid=949910

解题思路:

分析3 × f(n) × f(2n + 1) =f(2n) × (1 + 3f(n)), f(2n) < 6 × f(n)可以发现,3*f(n),3*f(n)+1互素。又有限制条件f(2n)<6*f(n),可以推出f(2n)=3*f(n),f(2n+1)=3*f(n)+1。写出前几项:

f(1)=1,f(2)=3,f(3)=4,f(4)=9,f(5)=10,f(6)=12,f(7)=13,f(8)=27,f(9)=28...

f(1) = f(0012)=1=0013,f(2)=f(0102)=3=0103,f(3)=f(011)=4=0113…可以发现f(n)的功能其实就是把对应的n的二进制表示当作三进制来算。发现这个关系后,可以用数位dp算出1-n范围内mod K余数为r的数的个数,dp[p][r]表示从第p位开始余数为r的数的个数。转移为dp[p][r]+=dp[p-1][r-i*3p]。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<map>
#include<string>
#include<queue>
#include<vector>
#include<list>
#include<bitset>
//#pragma comment(linker,"/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
ll n;
int K;
int dig[100];
int fac[100];
ll dp[65][65537];
ll dfs(int p,int r,int is)
{
    if(p==-1)
    {
        return r==0;
    }
    ll res=0;
    if(!is&&dp[p][r]!=-1) return dp[p][r];
    int up=is?dig[p]:1;
    for(int i=0;i<=up;i++)
    {
        res+=dfs(p-1,(r-i*fac[p]+K)%K,is==1&&i==up);
    }
    if(!is) dp[p][r]=res;
    return res;
}
void solve()
{
    memset(dp,-1,sizeof dp);
    long long tmp=n;
    int len=0;
    while(tmp)
    {
        dig[len++]=tmp%2;
        tmp/=2;
    }
    ll ans=0;
    for(int i=0;i<K;i++) ans^=dfs(len-1,i,1)-(i==0);
    printf("%lld\n",ans);
}
int main()
{
    int t;
    fac[0]=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%d",&n,&K);
        for(int i=1;i<100;i++) fac[i]=fac[i-1]*3%K;
        solve();
    }
   return 0;
}


 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值