称霸 题解
TinyKiecoo · · 个人记录
做法一
全部输出 -l,由于出题人凉心,本做法能得
做法二
对于每名选手只暴露一次弱点的情况,我们可以直接循环处理。遇到
做法三
每个回合最多只有两种状态,即积攒力量或者发起挑战。我们可以枚举每个回合的操作,找遍所有可能的状态,选回合数最少的。时间复杂度
#include<cstdio>
int n,m,a[10001],ans,cp,cm,b[10001];
bool f[10001];
void dfs(int day) {
if(ans<=day-1)return;
else if(cm==m) {
ans=day-1;
return;
}
else if(a[day]&&(!f[a[day]])&&cp>=b[a[day]]) {
f[a[day]]=1;
cp-=b[a[day]];
++cm;
dfs(day+1);
cp+=b[a[day]];
f[a[day]]=0;
--cm;
}
++cp;
dfs(day+1);
--cp;
}
int main() {
scanf("%d%d",&n,&m);
ans=n+1;
for(int i=1; i<=n; ++i)scanf("%d",&a[i]);
for(int i=1; i<=m; i++)scanf("%d",&b[i]);
dfs(1);
if(ans==n+1)puts("-l");
else printf("%d",ans);
}
做法四
发现答案是有单调性的,我们可以二分答案,然后判断是否合法。
判断使用贪心思路:在有限回合内,我们必然尽可能后挑战所有人,因为我们只需判断答案是否合法,则越后挑战,力量越大,成功的可能越高。
即对每个人,我们选他在特定回合数内,出现的最后一次作为挑战回合,其余积累力量就好。
经过分析,二分复杂度
#include <bits/stdc++.h>
using namespace std;
const int maxn=1111111;
int A[maxn],B[maxn],C[maxn],N,M;
bool vis[maxn];
bool check(int n)
{
memset(vis,0,sizeof(vis));
for(int i=n;i>=1;--i)
{
if(vis[A[i]]) C[i]=0;
else vis[A[i]]=true,C[i]=A[i];
}
int nw=0,cnt=0;
for(int i=1;i<=n;++i)
{
if(C[i]) nw-=B[A[i]],++cnt;
else ++nw;
if(nw<0) return false;
}
return cnt==M;
}
int main()
{
scanf("%d%d",&N,&M);
for(int i=1;i<=N;++i) scanf("%d",A+i);
for(int i=1;i<=M;++i) scanf("%d",B+i);
int l=1,r=N,ans=-1;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
if(ans!=-1) printf("%d\n",ans);
else puts("-l");
return 0;
}