HDU 5981 Guess the number

HDU 5981 Guess the number

原题链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5981

题目大意是:

A 在区间 [a,b] 上猜一个数字, B 猜测 A 猜测的数字。如果 B 猜测小了 A 会告诉他,一旦 B 猜测的大了。 A 不会再告诉 B ,直到B猜到这个数字为止 游戏结束。

问,在 B 每次做决定后。情况最差时。最少猜测多少次。

那么猜测次数明显和 a,b 无关。而与 ba+1 即区间长度有关。

对于长度为 L 的区间。定义最少猜测次数为
dp[L]

显然:
dp[L]=mink=1L(max( k1, dp[Lk] ))

特别的 dp[0]=0 ; dp[1]=1 ; dp[2]=2 

显然: dp[L]dp[L+1]dp[L+1]dp[L]1

则函数 dp[Lx] 的值域是 [ 0,dp[L]] 所有整数。

则:函数 f(x)=x1 与函数 g(x)=dp[Lx] 可能在交点。

并不一定存在交点。(这点想清楚有利于下面实现优化)

因为。 f(x) 是单调不降。 g(x) 单调不增。

随着 L 的改变, g(x) 图像向右平移。 f(x) 不动。所以最小值时的最大的k有可能增加。但不会减少。

维护这样一个 k 。使得 dp[Lk]k1 的最小的 k (为什么这样。可以画图细细体会。

即如下代码:

while(dp[L-k]>k-1)k++

结束循环时的 k 即为最佳。(当然然最佳选择不唯一)

那么与 dp[Lk]=k1 dp[Lk]k 相等的所有 k 可以选择。

如果 dp[Lk]<k1 。由递推关系可得。 dp[Lk] 也可以用。

这些都可以选择的方案用来维护方案数量。

记为 S[]

其中 S[0]=0 ; S[1]=1 ; S[2]=2

#include 
#include 
#include 
#define MAXN 5000010
using namespace std;
typedef long long LL;
const int P=100000073;
struct Bf
{
    int A[MAXN];
    Bf()
    {
        for(int i=0;iint find(int a)
    {
        if(a==A[a])return a;
        return A[a]=find(A[a]);
    }
}B;
int dp[MAXN];
int S[MAXN];

int main ()
{
    dp[1]=S[1]=1;
    dp[2]=2;
    S[2]=3;
    int k=2;
    for(int x=3;xwhile(dp[x-k]>k-1)k++;
        dp[x]=k;
        int b;
        if(dp[x-k]==k-1)
            b=B.find(x-k);
        else
            b=B.find(x-k+1);
        S[x]=(S[x-1]+S[b]-S[x-k-1]+P)%P;
        if(dp[x]==dp[x-1])B.A[x-1]=x;
    }
    int a,b;
    while(scanf("%d %d",&a,&b)==2)
    {
        int x=b-a+1;
        printf("%d %d\n",dp[x],(S[x]-S[x-1]+P)%P);
    }
    return 0;
}

你可能感兴趣的:(刷题小结,动态规划,链表)