P2060 猜数游戏

P2060\(\mathbf{} \begin{Bmatrix} \frac{{\Large SLOJ-P2060} }{{\color{Red}\Large Solution} }\mathbf{} {No.19} \end{Bmatrix}\times{}\) NeeDna

题意

一个简单的猜数游戏,NPC 先在 \([L,R)\) 中选择一个整数,然后 由你猜数,每次 NPC 会告诉你所猜之数是大于还是小于等于原数。

另外,当大于这一情况返回 \(K\) 次时,你 便不能继续猜数了。当 你成功把数范围缩小到 \([P,P+1)\) 时即算胜利。

但 NPC 十分狡猾,他会根据你的猜测临时变更原数,使你猜数次数尽可能多,现在你采用最佳策略猜数,请算出他猜出原数的步数。

第一行三个整数 \(L\)\(R\)\(K\) 含义如上所示。

题解

发现这个题次数只和 \(L-R\)\(K\) 有关,因为你要算的是一个长度下的 \(ans\) 。所以自然和 \(L\),\(R\) 的具体值无关,然后写出dp

\(i\) 为用了多少次大于,\(j\) 为区间大小,代码里 dp 的符号顺序有点不同)

{dpi,j=min(dpi,j,max(dpi1,x,dpi,jx)),x[1,j)dp1,j=j1dpi,1=0

打出来发现过了??? \(2e10\) 是怎么过的,但是无需在意,优化的话第一个转移有单调性,可以用单调队列优化,但是我懒得写了。

code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int f[5010][1010],l,r,k,n;
signed main(){
	memset(f,127,sizeof(f));
	cin>>l>>r>>k;n=r-l;
	for(int i=1;i<=n;i++) f[i][1]=i-1;
	for(int i=1;i<=k;i++) f[1][i]=0;
	for(int i=2;i<=k;i++){
		for(int j=2;j<=n;j++){
			for(int kk=1;kk<=j;kk++){
				f[j][i]=min(f[j][i],max(f[kk][i-1],f[j-kk][i])+1);
			}
		}
	}
	cout<<f[n][k];
	return 0;
} 

AI's better code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int f[5010][1010],l,r,k,n;
signed main(){
    memset(f,127,sizeof(f));
    cin>>l>>r>>k;n=r-l;
    for(int i=1;i<=n;i++) f[i][1]=i-1;
    for(int i=1;i<=k;i++) f[1][i]=0;
    for(int i=2;i<=k;i++){
        int opt=1;
        for(int j=2;j<=n;j++){
            while(opt<j&&max(f[opt][i-1],f[j-opt][i])>=max(f[opt+1][i-1],f[j-(opt+1)][i])) opt++;
            f[j][i]=max(f[opt][i-1],f[j-opt][i])+1;
        }
    }
    cout<<f[n][k];
    return 0;
}

update 2025.6.4 -- AI优化后的代码给出

posted @ 2025-05-30 21:08  NeeDna  阅读(21)  评论(0)    收藏  举报