Codeforces Round #625 div1 C.World of Darkraft: Battle for Azathoth & D.Reachable Strings

C. World of Darkraft: Battle for Azathoth

  題意:有n把武器,m件盔甲,每件武器有攻擊力Ai和價格CAi,每件盔甲有防禦力Bj和價格CBj,現需購買一把武器和一副

             盔甲。 另外有p個怪,每個怪有防禦力Xk、攻擊力Yk以及擊殺獎勵Zk,一個怪被擊殺當且僅當 購買武器的攻擊力大

             於怪物 防禦力,盔甲防禦力大於怪物攻擊力,即Ai > Xk 且 Bj >Yk,問最大收益。

 

  題解:。。將每把武器的初始收益置爲-CAi,然後按防禦力小到大枚舉每件盔甲,同時雙指針不斷更新攻擊力小於當前盔甲防

            御力的怪k,那麼攻擊力大於Xk的武器收益都會增加 Zk,答案就是武器收益-盔甲價格的最大值。。。所以線段樹區間

            覆蓋維護最大值。。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ma[1000000],lazy[1000000];
void down(int x){
   if(lazy[x]){
       ma[x*2]+=lazy[x];
       lazy[x*2]+=lazy[x];
       ma[x*2+1]+=lazy[x];
       lazy[x*2+1]+=lazy[x];
       lazy[x]=0;
   }
}
void update(int root,int l,int r,int L,int R,int v){
    if(l==L&&r==R){
        lazy[root]+=v;
        ma[root]+=v;
        return;
    }
    down(root);
    int mid=(l+r)/2;
    if(R<=mid) update(root*2,l,mid,L,R,v);
    else if(L>mid) update(root*2+1,mid+1,r,L,R,v);
    else{
        update(root*2,l,mid,L,mid,v);
        update(root*2+1,mid+1,r,mid+1,R,v);
    }
    ma[root]=max(ma[root*2],ma[root*2+1]);
}

int ha[200010];
struct Q{
    int a,b,c;
}A[200010],B[200010],C[200010];
int cmp1(Q a,Q b){
    return a.a<b.a;
}
int cmp2(Q a,Q b){
    return a.b<b.b;
}

int main(){
    int i,n,m,p;
    cin>>n>>m>>p;
    for(i=1;i<=n;i++) scanf("%d%d",&A[i].a,&A[i].b);
    for(i=1;i<=m;i++) scanf("%d%d",&B[i].a,&B[i].b);
    for(i=1;i<=p;i++) scanf("%d%d%d",&C[i].a,&C[i].b,&C[i].c);
    sort(A+1,A+1+n,cmp1);
    sort(B+1,B+1+m,cmp1);
    sort(C+1,C+1+p,cmp2);
    for(i=1;i<=n;i++){
        update(1,1,n,i,i,-A[i].b);
        ha[i]=A[i].a;
    }
    int k=1,a;
    ll ans=-1e18;
    for(i=1;i<=m;i++){
        while(k<=p&&C[k].b<B[i].a){
           a=upper_bound(ha+1,ha+1+n,C[k].a)-ha;
           if(a<=n) update(1,1,n,a,n,C[k].c);
           k++;
        }
        ans=max(ans,ma[1]-B[i].b);
    }
    cout<<ans<<endl;
}

 

 

D. Reachable Strings

   題意:給一個長度爲 n <= 2e5 的01串S,每次可將任意子串011變成110 或者將110變成011。q <=2e5 次詢問,每次詢問S的

             兩個子串 ,即S [l1...r1] 能否通過任意次變換變成 S[l2..r2]。

 

   題解:對於每次變換,可以發現都是將一個0往左或往右移動兩位且之間爲兩個1,將這兩個串中的0都儘量往某方向(左或

            右) 移動,如果移動之後兩串長得一樣,則這兩原串間可相互變換。(如果兩個串不能相互轉化,那麼把所有0都

            移向某方向後顯然是不一樣的)。而一個0每次都是和 相鄰的 11 交換位置,所以移動前後,相鄰兩個0之間1的個數奇

            偶不變,將每個0的權值設爲與前一個0之間1個數的奇偶,那麼即可通過hash值來判斷這兩串向某方移動後是否一樣了。

            最後注意下每個子串中第一個0的權值。。。

            。。。還有就是如果 hash 用 二進制 + unsigned long long自然溢出的話會WA10......改爲其它進制即可。。

 

#include<bits/stdc++.h>
using namespace std;

char s[200010];
typedef unsigned long long ull;
int A[200010],B[200010],sum[200010],cnt;
ull p[200010],ha[200010];

ull f(int l,int r){
    int len=r-l+1;
    return ha[r]-ha[l-1]*p[len];
}
ull ff(int a,int b){
    int l=lower_bound(A+1,A+1+cnt,a)-A,r=upper_bound(A+1,A+1+cnt,b)-A-1;
    ull val,x;
    if(l<=r){
        x=(A[l]-a)%2;
        val=x*p[r-l];
        if(l<r) val+=f(l+1,r);
        return val;
    }
    return 0;
}
int main(){
    int i,n,m,num=0,l1,l2,len,r1,r2;
    p[0]=1;
    for(i=1;i<=200005;i++) p[i]=p[i-1]*5;
    scanf("%d",&n);
    scanf("%s",s+1);
    for(i=1;s[i];i++){
        sum[i]=sum[i-1];
        if(s[i]=='1') num++;
        else{
            B[++cnt]=num%2;
            num=0;
            A[cnt]=i;
            sum[i]++;
        }
    }
    for(i=1;i<=cnt;i++) ha[i]=ha[i-1]*5+B[i];
    scanf("%d",&m);
    while(m--){
       scanf("%d%d%d",&l1,&l2,&len);
       r1=l1+len-1;
       r2=l2+len-1;
       if(sum[r1]-sum[l1-1]==sum[r2]-sum[l2-1]&&ff(l1,r1)==ff(l2,r2)) printf("Yes\n");
       else printf("No\n");
   }
   return 0;
}

            

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章