Timus 1117

纠结了一天也没有想到怎么用DP来做,看了看大牛的想法顿时茅塞顿开:

结果是要求从i到j需要多少天,假如用res[i][j]来表示,那么假如我们知道res[1][i]和res[1][j]的话,res[i][j]=res[1][j]-res[1][i] (i<=j),因此转化为求res[1][i]和res[1][j];

而2的整数次幂可以直接求出若用r[i]表示res[1][2^i]的结果r[i]=2*r[i-1]+i-1;画一画就可以看得出来。

然后根据r[i]的值递归求任何一个res[1][k],如何递归呢?

拿个Res[1][11]来说吧:

先找出大于11的最大2的整数次幂8;

Res[1][11]=res[1][8]+res[8][11];

根据对称性可以将res[8][11]变为res[5][8],因此

Res[1][11]=res[1][8]+res[5][8]=res[1][8]+(res[1][8]-res[1][5])=2*res[1][8]-res[1][5];

最终 res[1][11]=2*res[1][8]-res[1][5]; 还可以将res[1][5]不断分解。

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

unsigned int res[35];

int findLayer(unsigned int k)

{

    int i;

    for(i=0;i<=31;i++)

        if((unsigned int)(1<<i)>k) return i-1;

    return 0;

}

int dfs(int k)

{

    int layer=findLayer(k);

    if(1<<layer==k) return res[layer];

    return 2*res[layer]-dfs((1<<(layer+1))-k);

}

int main()

{

    int i,s,t,temp;

    for(i=1;i<=31;i++) res[i]=2*res[i-1]+i-1;

    while(scanf("%d %d",&s,&t)!=EOF)

    {

        if(s>t) temp=s,s=t,t=temp;

        printf("%d\n",dfs(t)-dfs(s));

    }

    return 0;

}

你可能感兴趣的:(IM)