题解:P13872 [蓝桥杯 2024 省 Java/Python A] 砍柴
拿到题目,我们首先注意到这是一个“公平组合游戏”,即可以进行的选择与角色无关(与之相对应的如常见的棋类,因为你不能动别人的棋)。
于是我们可以设一个一维布尔数组
这个时候,我们再考虑对于一个元素
由这个结论,我们可以考虑转移方程:
其中
边界是
答案是
然后我们来考虑这种做法的时间复杂度。我们可以使用如下公式来估算
由于外层枚举
再加上
接下来是代码(C++):
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
bool inp[N+10];//标记每个数字是否不是质数。
vector<int> prime;//质数表
int dp[N+10];//递推数组
int main(){
for(int i=2;i<=N;i++){
if(!inp[i]) prime.push_back(i);//如果不是非质数(是质数)
for(int j=0;j<prime.size()&&i*prime[j]<=N;j++){//用以筛掉非质数(线性筛)
inp[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
for(int i=2;i<=N;i++){//递推
for(auto j:prime){
if(j>i) break;//判断是否在范围内
dp[i]=dp[i] || (!dp[i-j]);//只要有一个操作让对手必败就行,否则就是不行。
}
}
int t;
cin>>t;
while(t--){
int n;
cin>>n;
cout<<dp[n]<<'\n';//每次读入然后输出。
}
}
然后是 python 版(需要 pypy3 提交):
N=(10**5)+7
inp=[False for i in range(N+10)]
prime=[]
dp=[False,False]
for i in range(2,N+1):
if not inp[i]:
prime.append(i)
for j in range(0,len(prime)):
if i*prime[j]>N:
break
inp[i*prime[j]]=True
if i%prime[j]==0:
break
for i in range(2,N+1):
dp.append(False)
if not inp[i] or not inp[i-1]:#一点小优化,不然过不了。python常数太大了
dp[i]=1
else:
for j in prime:
if j>i:
break
dp[i]=dp[i] or (not dp[i-j])
t=int(input())
for i in range(t):
p=int(input())
print(int(dp[p]))