zoukankan      html  css  js  c++  java
  • Codeforces1257D (贪心+缓存,或者二分+线段树)

    题目大意:有n个怪物,每个怪物都有一个能力值a。有m个勇士,每个勇士都有一个力量P和耐力S。明天可以选择一个勇士去打怪物,必须按顺序打,如果这个勇士的能力P>=a那么就可以打败这个怪物,就必须打下一个怪物,而且最多一天只能打S个怪物。如果力量P<a。这个勇士就回来。这天结束,每个勇士可以使用无数次。问最少需要多少天,能把所有的怪物全部打败。

    给的数据范围分别是  n(1<=n<=2e5),  m(1<=m<=2e5)     (1<=pi<=1e9,1<=si<=n)    所有询问的n+m加起来不超过2e5

    这道题一个很正常的思路(或者说我的一般思路是)     首先我们怎么来求解决了前i只怪物的最小时间?????   

    那么就可以考虑解决第i个怪物的勇士他所解决的区间的问题,这样的操作可以二分解决,然后在用线段树维护?????

    但是感觉这样有点难写?而且很容易wa,我就wa了不知道多少遍。

    下面是比赛时写的代码:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <cmath>
      6 #include <bitset>
      7 #include <set>
      8 typedef long long ll;
      9 using namespace std;
     10 const int maxn=201000;
     11 int t,n,m;
     12 int num[maxn],sum1[maxn<<2],sum2[maxn<<2],dp[maxn],q[maxn],p[maxn],s[maxn];
     13 struct node{
     14     int pi,si;
     15 };
     16 node fnum[maxn];
     17  
     18 bool cmp(node n1,node n2){
     19     if(n1.pi==n2.pi) return n1.si<n2.si;
     20     else return  n1.pi<n2.pi;
     21 }
     22  
     23 void build1(int l,int r,int rt){
     24     if(l==r){
     25         sum1[rt]=num[l];
     26         return;
     27     }
     28     int mid=(l+r)/2;
     29     build1(l,mid,rt<<1);
     30     build1(mid+1,r,rt<<1|1);
     31     sum1[rt]=max(sum1[rt<<1],sum1[rt<<1|1]);
     32 }
     33  
     34 int ask(int l,int r,int rt,int L,int R){
     35     if(L<=l&&r<=R) return sum1[rt];
     36     int mid=(l+r)/2;
     37     int ans=0;
     38     if(L<=mid) ans=max(ans,ask(l,mid,rt<<1,L,R));
     39     if(R>mid) ans=max(ans,ask(mid+1,r,rt<<1|1,L,R));
     40     return ans;
     41 }
     42  
     43 void adds(int l,int r,int rt,int k,int k1){
     44     if(l==r){
     45         sum2[rt]=k1;
     46         return;
     47     }
     48     int mid=(l+r)/2;
     49     if(k<=mid) adds(l,mid,rt<<1,k,k1);
     50     else  adds(mid+1,r,rt<<1|1,k,k1);
     51     sum2[rt]=min(sum2[rt<<1|1],sum2[rt<<1]);
     52 }
     53  
     54 int Min(int l,int r,int rt,int L,int R){
     55     if(L<=l&&r<=R) return sum2[rt];
     56     int mid=(l+r)/2;
     57     int ans=(int)(1e9+7);
     58     if(L<=mid) ans=min(ans,Min(l,mid,rt<<1,L,R));
     59     if(R>mid) ans=min(ans,Min(mid+1,r,rt<<1|1,L,R));
     60     return ans;
     61 }
     62  
     63  
     64 bool check(int l,int  r){
     65     int q1=ask(1,n,1,l,r);
     66     int iscan=(int)(lower_bound(p+1,p+m+1,q1)-p);
     67     //if(l==1&&r==2) printf("%d  %d  %d %d
    ",q1,num[1],num[2],iscan);
     68     if(iscan>=1&&iscan<=m&&q[iscan]>=(r-l+1)) return true;
     69     return false;
     70 }
     71  
     72 int main(){
     73     scanf("%d",&t);
     74     while(t--){
     75         scanf("%d",&n);
     76         for(int i=1;i<=n;i++) scanf("%d",&num[i]);
     77         build1(1,n,1);
     78         scanf("%d",&m);
     79         for(int i=1;i<=m;i++) scanf("%d%d",&fnum[i].pi,&fnum[i].si);
     80         sort(fnum+1,fnum+m+1,cmp);
     81         int flag=0;
     82         for(int i=1;i<=m;i++){
     83             //if(fnum[i].pi<num[i])  flag=1;
     84             p[i]=fnum[i].pi;s[i]=fnum[i].si;
     85         }
     86         for(int i=1;i<=n;i++) if(fnum[m].pi<num[i]) flag=1;
     87         if(flag==1){printf("-1
    ");continue;}
     88  
     89         q[m]=fnum[m].si;
     90         for(int i=m-1;i>=1;i--)  q[i]=max(q[i+1],s[i]);
     91  
     92         dp[1]=1;dp[0]=0;
     93         adds(0,n,1,1,1);   adds(0,n,1,0,0);
     94         for(int i=2;i<=n;i++){
     95             int l=1,r=i,ans=i;
     96             while(l<=r){
     97                 int mid=(l+r)/2;
     98                 if(check(mid,i)==1){ans=mid;r=mid-1;}
     99                 else l=mid+1;
    100             }
    101             // cout<<ans-1<<"  "<<i-1<<endl;
    102             dp[i]=Min(0,n,1,ans-1,i-1)+1;
    103             adds(0,n,1,i,dp[i]);
    104         }
    105         printf("%d
    ",dp[n]);
    106     }
    107     return 0;
    108 }
    View Code

    然后就是一个很妙的解法了,我也不知道怎么才能在考试里面想到这样的解法??????

    tql!!!

    (1):首先我们可以发现这个东西是可以贪心的,就是对于每个勇士他可以杀的怪兽越多越好,总而言之就是能啥多只怪兽就啥多少怪兽,直接贪心下去就ok了

    (2):然后我们需要抛弃m这个东东,因为没啥用,考虑能连续作战i天的勇士的fi的最大值,这样的话我们如果能坚持i天,就直接撸下去,而不需要考虑那个特定的勇士

    (3):直接将值域映射到i上面,这样是最好做的

    下面是代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #include <iostream>
     5 #include <cmath>
     6 #include <bitset>
     7 typedef long long ll;
     8 using namespace std;
     9 const int maxn=201000;
    10 int num[maxn],mx[maxn];
    11 int t,n,m;
    12 int main(){
    13     scanf("%d",&t);
    14     while(t--){
    15         scanf("%d",&n);
    16         for(int i=1;i<=n;i++) scanf("%d",&num[i]);
    17         for(int i=1;i<=n;i++) mx[i]=0;
    18         scanf("%d",&m);
    19         for(int i=1;i<=m;i++){
    20             int pi,si;
    21             scanf("%d%d",&pi,&si);
    22             mx[si]=max(mx[si],pi);
    23         }
    24         for(int i=n-1;i>=1;i--)  mx[i]=max(mx[i],mx[i+1]);
    25 
    26         int pos=1,flag=1,day=0;
    27         while(pos<=n){
    28             day++; int tmp=pos,maxn=0;
    29             while(tmp<=n){
    30                 maxn=max(maxn,num[tmp]);
    31                 if(maxn>mx[tmp-pos+1]) break;
    32                 ++tmp;
    33             }
    34             if(tmp==pos){
    35                 flag=0;break;
    36             }
    37             pos=tmp;
    38         }
    39         if(!flag) day=-1;
    40         printf("%d
    ",day);
    41     }
    42     return 0;
    43 }
    View Code
  • 相关阅读:
    C# 读取JSON
    checkbox与说明文字无法对齐的问题
    C#判断一个string是否为数字
    C# 调用系统winmm.dll 播放音乐wav mp3
    C#导出EXCEL的几种方法
    C#遍历DataSet中数据的几种方法总结
    cookie 简单用法
    JQGrid 在页面加载时展开SubGrid
    Echarts 设置地图上文字大小及颜色
    Echarts 地图上显示数值
  • 原文地址:https://www.cnblogs.com/pandaking/p/12035028.html
Copyright © 2011-2022 走看看