题解:P9670 [ICPC2022 Jinan R] Frozen Scoreboard
Field_Mouse · · 题解
马上打 ICPC 了写篇题解涨涨 rp /kel
题意简述&题意分析
这一题最难的部分就是看懂题面,看懂了就是纯模拟。
给你 ICPC 队伍前四小时的提交记录,求出一种可能的最终得分。共
我们约定输入中的符号如下意:
由题目中的罚时可得,此题的用时认为是
这题的罚时记为
显然以上三种情况不用处理,直接保留到最终结果即可。
这是本题唯一需要处理的部分。
做法简述
我们直接保留除了
而未知用时的题目只有
时间复杂度是
细节看代码注释。
#include<bits/stdc++.h>
#define AC return 0;
#define pr(n) printf("%d",(n))
#define hh puts("")
#define kg printf(" ")
using namespace std;
namespace fr{
int read()
{
int x=0,flag=1;
char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')flag=-1;
for(;ch<='9'&&ch>='0';ch=getchar())x=(x<<3)+(x<<1)+ch-'0';
return flag*x;
}
}
using namespace fr;
const int N = 1e3+3;
struct node{
char opt;
int x,y;
}ans[N],kn[N];
int a,b;
int n=read(),m=read();
vector<int> yiw;
int tims,cnt;
bool flag;
void init()
{
a=read(),b=read();
tims=0,cnt=0;
yiw.clear();
for(int i=1;i<=m;i++)
{
char c;
cin>>c;
kn[i].opt=c;
if(c=='.'){ans[i].opt='.';continue;}
if(c=='+')
{
++cnt;
kn[i].x=read(),kn[i].y=read();
tims+=20*(kn[i].x-1)+kn[i].y;//罚时/kel
ans[i]=kn[i];
}
if(c=='-')
{
kn[i].y=read();
ans[i]=kn[i];
}
if(c=='?')
{
kn[i].x=read(),kn[i].y=read();
yiw.push_back(i);
}
}//处理输入,/yiw存尚且不确定的几个结果,下面处理
}
void out()
{
if(!flag){puts("No");return ;}
puts("Yes");
for(int i=1;i<=m;i++)
{
if(ans[i].opt=='.'){puts(".");continue;}
if(ans[i].opt=='+'){cout<<"+ "<<ans[i].x<<"/"<<ans[i].y<<endl;continue;}
if(ans[i].opt=='-'){cout<<"- "<<ans[i].y<<endl;continue;}
}
}
void sol()
{
init();
int T = yiw.size();
flag=0;
for(int i=0;i<(1<<T);++i)//直接枚举全部子集
{
int ncnt=cnt,maxn=tims,minn=tims;
for(int j=0;j<T;++j)
{
if((i>>j)&1)
{
++ncnt;
minn+=240+20*(kn[yiw[j]].y-kn[yiw[j]].x);
maxn+=299+20*(kn[yiw[j]].y-1);
}
}//求出当前方案罚时的取值范围
if(ncnt==a&&minn<=b&&b<=maxn)//有解
{
flag=1;
b-=minn;//可以直接消去当前方案的最小罚时
for(int j=0;j<T;++j)
{
if((i>>j)^1)ans[yiw[j]].opt='-',ans[yiw[j]].y=kn[yiw[j]].y;//不选睡觉
if((i>>j)&1)//选择这一题
{
ans[yiw[j]].opt='+';
int l=240+20*(kn[yiw[j]].y-kn[yiw[j]].x);
int r=299+20*(kn[yiw[j]].y-1);//当前最大可能时间与最小可能时间
if(b>=r-l)
{
b-=r-l;
ans[yiw[j]].x=kn[yiw[j]].y;
ans[yiw[j]].y=299;//罚时还很多
}
else if(!b)
{
ans[yiw[j]].x=kn[yiw[j]].y-kn[yiw[j]].x+1;
ans[yiw[j]].y=240;//罚时不够了
}
else
{
for(int k=0;k<kn[yiw[j]].x;++k)
{
int now=b-k*20;
if(0<=now&&now<=59)
{
ans[yiw[j]].x=kn[yiw[j]].y-kn[yiw[j]].x+k+1;
ans[yiw[j]].y=240+now;
b=0;
break;//罚时还剩一点
}
}
}
}
}
}//重复枚举这个方案
}
out();
}
int main()
{
while(n--){
sol();
}
AC
}