概述
cf传送门
vj传送门
首先注意到
a
i
<
=
100
a_i<=100
ai<=100,也就是每次最多花费
100
100
100,然后由于每次可以充
100
100
100,那么其实当前的余额可以维持在
[
0
,
100
)
[0,100)
[0,100)的范围以内(第一次除外)。考虑余额到达某个状态
u
u
u所需要的最少物品数,记作
d
p
[
u
]
dp[u]
dp[u],可以从状态
0
0
0出发通过
b
f
s
bfs
bfs更新出所有的可达状态以及其
d
p
dp
dp值。然后由于每个物品出现的概率都是
1
2
frac 12
21,我们每天都检查当前的所有物品是否存在一个物品使得当前状态的
d
p
dp
dp值变小即可。
d
p
dp
dp值变小的概率至少为
1
2
frac 12
21,因此
365
365
365天必定可以让余额归零。注意两点:1.当余额变成负数的时候,只需要充一百即可,正常情况下其实没必要充钱,以便让状态维持在
[
0
,
100
)
[0,100)
[0,100),由于
d
p
dp
dp值最大其实是
100
100
100(鸽笼原理),因此通过上述方式能够让余额归零。2.最开始的时候余额可能是100,为了便于处理,我们任意减去一个物品即可,后面就可以正常的按照计划进行了。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 505;
const int inf = 2147483647;
typedef long long ll;
int a[maxn<<1],dp[maxn],vis[maxn];
queue<int>q;
int main(){
int n,p;
scanf("%d%d",&n,&p);
for(int i=1;i<=2*n;++i){
scanf("%d",&a[i]);
}
q.push(0);
vis[0]=1;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=1;i<=2*n;++i){
int v=(u+a[i])%100;
if(vis[v])continue;
vis[v]=1;
dp[v]=dp[u]+1;
q.push(v);
}
}
for(int t=1;t<=365;++t){
bool ok=false;
for(int i=1;i<=n;++i){
int u;scanf("%d",&u);
int to;
if(p==100){
to=p-a[u];
ok=true;
printf("0 %dn",u);
fflush(stdout);
p=to;
for(int j=i+1;j<=n;++j)scanf("%d",&u);
if(!p)return 0;
break;
}else to=(p-a[u]+100)%100;
if(dp[to]<dp[p]){
int c=0;
if(p<a[u])c=1;
printf("%d %dn",c,u);
ok=true;
fflush(stdout);
p=to;
for(int j=i+1;j<=n;++j)scanf("%d",&u);
if(!p)return 0;
break;
}
}
if(!ok){
printf("0 0n");
fflush(stdout);
}
}
}
最后
以上就是怕黑外套为你收集整理的acm-(交互、bfs、dp)2018 ECNU Campus Invitational Contest E. Balance Reset的全部内容,希望文章能够帮你解决acm-(交互、bfs、dp)2018 ECNU Campus Invitational Contest E. Balance Reset所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复