zoj 3845 Fixed Point(数位dp)

题目链接

Fixed Point

Time Limit: 2 Seconds      Memory Limit: 65536 KB

In mathematics, a fixed point (sometimes shortened to fixpoint, also known as an invariant point) of a function is an element of the function's domain that is mapped to itself by the function. A set of fixed points is sometimes called a fixed set. That is to say, c is a fixed point of the function f(x) if and only if f(c) = c. This means f(f(...f(c)...)) = fn(c) = c, an important terminating consideration when recursively computing f. For example, if f is defined on the real numbers by f(x) = x2 - 3x + 4, then 2 is a fixed point of f, because f(2) = 2.

Bob has three funtions define on nonegative integers, A(x) = cx, E(x) = cx, and O(x) = cx, where ∧ means bitwise AND operation, ⊕ means bitwise XOR operation, ∨ means bitwise OR operation and c is an integer constant.

Bob wants to know the number of fixed points for each function which satisfy the following conditions:

  1. x is no less than L and x is also no greater than R.
  2. Let c0 be the number of 0-bit in x's binary representation and c1 be the number of 1-bit in x's binary representation. Then we have |c0 - c1| ≤ k.

You are given three integers L, R and k, please tell Bob the answer.

Note: x is a 32-bit integer, that is x's binary representation only has 32 bits.

Input

The first line of input contain an integer T (T ≤ 10000), which is the number of cases.

Then next T line, each line contain four integers L, R, c and k (0 ≤ LR < 232, 0 ≤ c < 232, 0 ≤ k ≤ 32), separated by spaces.

Output

For each test case, print a line containing the test case number (beginning with 1) followed by three integers, indicating the number of fixed points for function A(x), E(x) and O(x), separated by one space.

Sample Input
3
1 10 1 32
1 100 43 32
1 200 43 20
Sample Output
Case 1: 1 0 5
Case 2: 15 0 4
Case 3: 0 0 7

题意:A(x)=c&x,  B(x)=c^x,C(x)=c|x。分别求出在[L,R]的范围内,满足A(x)=x,B(x)=x,C(x)=x,且32位二进制表示中1的个数和0的个数的差的绝对值小于等于k的数的个数。

题解:由于数的范围较大,所以要用数位统计的方法。先将数转换到二进制。用dp[i][j] 表示从32位到第i位的数,二进制0,1的绝对值之差为j,由当前状态变到目标状态的数的个数。转移的时候分别满足A(x)=x,B(x)=x.C(x)=x的条件。

代码如下:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<string>
#include<stack>
#include<math.h>
#include<vector>
#include<set>
#include<map>
#define nn 110000
#define inff 0x7fffffff
#define eps 1e-8
#define mod 1000000007
typedef long long LL;
const LL inf64=LL(inff)*inff;
using namespace std;
LL l,r,c,k;
LL wc[40];
LL wei[40];
LL dp[40][70];
LL dfs(int id,int s,int ty,bool man)
{
    if(id==-1)
    {
        if(abs(s-35)<=k)
            return 1;
        return 0;
    }
    if(!man&&dp[id][s]!=-1)
        return dp[id][s];
    int end=man?wei[id]:1;
    LL re=0;
    for(int i=0;i<=end;i++)
    {
        if(ty==1)
        {
            if((wc[id]&i)==i)
            {
                if(i==0)
                    re+=dfs(id-1,s-1,ty,man&&i==end);
                else
                    re+=dfs(id-1,s+1,ty,man&&i==end);
            }
        }
        if(ty==2)
        {
            if((wc[id]^i)==i)
                re+=dfs(id-1,i==0?(s-1):(s+1),ty,man&&i==end);
        }
        if(ty==3)
        {
            if((wc[id]|i)==i)
                re+=dfs(id-1,i==0?(s-1):(s+1),ty,man&&i==end);
        }
    }
    if(!man)
        dp[id][s]=re;
    return re;
}
LL solve(LL x,int ty)
{
    int ix=0;
    memset(wei,0,sizeof(wei));
    while(x)
    {
        wei[ix++]=x%2;
        x/=2;
    }
    return dfs(31,35,ty,true);
}
int main()
{
    int t,cas=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld%lld%lld",&l,&r,&c,&k);
        LL ans1,ans2,ans3;
        int ix=0;
        LL ic=c;
        memset(wc,0,sizeof(wc));
        while(c)
        {
            wc[ix++]=c%2;
            c/=2;
        }
        if(l==0)
        {
            memset(dp,-1,sizeof(dp));
            ans1=solve(r,1);
            memset(dp,-1,sizeof(dp));
            ans2=solve(r,2);
            memset(dp,-1,sizeof(dp));
            ans3=solve(r,3);
        }
        else
        {
            memset(dp,-1,sizeof(dp));
            ans1=solve(r,1)-solve(l-1,1);
            memset(dp,-1,sizeof(dp));
            ans2=solve(r,2)-solve(l-1,2);
            memset(dp,-1,sizeof(dp));
            ans3=solve(r,3)-solve(l-1,3);
        }
        printf("Case %d: ",cas++);
        printf("%lld %lld %lld\n",ans1,ans2,ans3);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值