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;
}

            

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值