第九届山东理工大学ACM网络编程擂台赛 F题题解

http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Contest/contestproblem/cid/2326/pid/4072

解题思路:
题目要求最短时间完成所有的考验,如果直接去求最短时间应该是不太现实的,因为这种思路既不符合贪心,又不能dp。仔细看不难发现,如果假设一个天数x,是可以通过从后往前贪心的方法去验证x天内是否可以完成所有的考验。
具体贪心方法是:假如x天之前都没有进行考验,那么对于第x天有x-1天的“空闲天”可以准备第x天的考验,于是从第x天向第0天判断每一天是不是有未完成考验,如果有就从空闲天中减去这个考验所需要的准备天数,依次维护空闲天数进行判断,最后判断一下是不是所有的考验都通过了即可。
但是如果从1到n枚举天数x是o(n^2)的复杂度,肯定是不行的,然后又发现假设天数y可以完成,那么天数大于y的都能完成,同样加入天数y不能完成,小于y的都不能完成,这就有了满足了二分判断所需要的性质,于是二分判断,复杂度满足题意。
代码:

#include <stdio.h>
#include <string.h>
const int Max = 1e6 + 100;
int vis[Max];
int data[Max], need[Max];
int isok(int n, int m){//判断n天是否可以完成m项考验
     int ans = n - 1, mem = 0, num = 0;
     memset(vis, 0, sizeof(vis));
     for (int a = n; a >= 0; a--){
          if (data[a] != 0 && !vis[data[a]] && ans >= need[data[a]]) {
               ans -= need[data[a]];
               mem += need[data[a]];
               vis[data[a]] = 1;
               if (++num == m)return 1;
               ans--;
          }
          else if (mem > 0)mem--;
          else ans--;
          if (ans <= 0)
          break;
     }
     return 0;
}
int main(){
     int T, n, m;
     scanf("%d", &T);
     while (T--){
          scanf("%d%d", &n, &m);
          for (int a = 1; a <= n; a++)scanf("%d", &data[a]);
          for (int a = 1; a <= m; a++)scanf("%d", &need[a]);
          int l = 1, r = n, ans = -1;
          while (l <= r){//二分判断
               int mid = (l + r) / 2;
               if (isok(mid, m)){
                    ans = mid;
                    r = mid - 1;
               }
               else{
                    l = mid + 1;
               }
          }
          printf("%d\n", ans);
     }
     return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值