SPOJ 20848 IGAME

来源:互联网 发布:怎样编程游戏 编辑:程序博客网 时间:2024/06/06 04:39

Description
两个人玩游戏,初始给一个整数n,两人轮流操作,每次可以选择n的一位在保证该位非负的情况下减去任意值,谁先把n减到0谁赢,问在双方足够机智的情况下[A,B]中有多少值作为初始值可以使得先手必胜,有多少值作为初始值可以使后手必胜
Input
第一行一整数T表示用例组数,每组用例输入两整数A和B表示查询区间(1<=T<=1e4,1=A<=B<=1e18)
Output
Sample Input
2
1 10
101 110
Sample Output
10 0
8 2
Solution
经典取石子问题,问题变成求[1,n]中有多少数的各位异或和不是0,简单数位dp,dp[pos][state]表示当前在第pos位,前pos-1位的异或和是state的方案数
Code

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#include<queue>#include<map>#include<set>#include<ctime>using namespace std;typedef long long ll;#define INF 0x3f3f3f3fll dp[22][22],A,B;int T,a[22];ll dfs(int pos,int state,int fp){    if(pos==0)    {        if(state)return 1;        return 0;    }    if(!fp&&dp[pos][state]!=-1)return dp[pos][state];    ll ans=0;    int fpmax=fp?a[pos]:9;    for(int i=0;i<=fpmax;i++)ans+=dfs(pos-1,state^i,fp&&i==fpmax);    if(!fp)dp[pos][state]=ans;    return ans;}ll Solve(ll n){    int res=0;    while(n)    {        a[++res]=n%10;        n/=10;    }    return dfs(res,0,1);}int main(){    memset(dp,-1,sizeof(dp));    scanf("%d",&T);    while(T--)    {        scanf("%lld%lld",&A,&B);        ll ans=Solve(B)-Solve(A-1);        printf("%lld %lld\n",ans,B-A+1-ans);    }    return 0;}
0 0
原创粉丝点击