2015 ACM/ICPC 北京賽區 現場賽 K —— A Math Problem【規律+數位dp】
阿新 • • 發佈:2018-12-12
題意:
給你兩個數n(n<=1e18),mod(mod=3,5,7,257,65537)
定義f(x):
f(1)=1;
已知:3*f(n)*f(2*n+1)=f(2*n)*(1+3*f(n));
f(2*n)<6*f(n);
將f(1)~f(n)%mod。
結果:求模之後結果為0~mod-1的數字的數量的異或。
分析:
這個題只要找出來規律就是一個簡單的數位dp,規律就是n寫成二進位制的方法,用三進位制來計算例如5=101,結果f[5]=101(三進位制)=10;
程式碼:
#include<bits/stdc++.h> #define ll long long #define inf 0x3f3f3f3f using namespace std; const int maxn=62; ll dp[maxn][5][65538]; int mp[65538],a[maxn],mm; int mo; ll n; int yu[maxn]; ll dfs(int pos,int v,bool limit) { if(pos==-1) return (v==0); if(!limit&&dp[pos][mm][v]!=-1) return dp[pos][mm][v]; ll ans=0; int end=limit?a[pos]:1; int vv=v; for(int i=0;i<=end;i++) { if(i&1) {v-=yu[pos];v=(v+mo)%mo;} ans+=dfs(pos-1,v,limit&&i==end); } if(!limit) dp[pos][mm][vv]=ans; return ans; } ll solve(ll x) { // cout<<x<<endl; mm=mp[mo]; yu[0]=1; for(int i=1;i<maxn;i++)yu[i]=(yu[i-1]*3)%mo; int pos=0; while(x) { a[pos++]=x&1; x>>=1; } ll ans=0; for(int i=0;i<mo;i++) { ans^=(dfs(pos-1,i,1)-(i==0)); //cout<<(dfs(pos-1,i,1)-(i==0))<<endl; } return ans; } int main() { mp[3]=0;mp[5]=1;mp[17]=2; mp[257]=3;mp[65537]=4; memset(dp,-1,sizeof(dp)); int T,cas=1; scanf("%d",&T); while(T--) { scanf("%lld%d",&n,&mo); printf("%lld\n",solve(n)); } return 0; }