Codeforces Round #546 (Div. 2)

A.Nastya Is Reading a Book

题意:一本书共有 n n n章,每章为 [ l i , r i ] [l_i,r_i] [li,ri],现在读到 k k k页,问剩下没读得包括当前章的章数。
题解:遍历一遍看第 k k k页再第几章, a n s = n − k + 1 ans=n-k+1 ans=nk+1

int l[111],r[111];
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>l[i]>>r[i];
    int m;
    cin>>m;
    for(int i=1;i<=n;i++){
        if(m>=l[i]&&m<=r[i]){
            cout<<n-i+1<<"\n";
            return 0;
        }
    }
    return 0;
}
 

B.Nastya Is Playing Computer Games

题意:有 n n n个井盖,每个井盖上有一个石头,每次可以将一个石头移到旁边一个井盖上,若没有石头则可以打开井盖获得硬币,问获得所有硬币的最小代价。
题解:若只有两个井盖,我们可以将石头移到另一个井盖上,然后打开井盖,再移动到下一个井盖,移动两个石头,打开井盖,共6个代价。那么当井盖数大于2时,我们只需要走到下一个井盖,将石头扔到上一个井盖,然后打开,共3个代价即可。若一开始的位置不再端点上,那么可以走到端点,加上这一部分代价,因为你无论怎么走最后都要有走的这一部分代价。

int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n,k;
    cin>>n>>k;
    cout<<3*n+min(k-1,n-k)<<"\n";
    return 0;
}

C.Nastya Is Transposing Matrices

题意:给你两个矩阵,问能否通过若干次子正方形矩阵转置得到两个相同的矩阵。
题解:每次矩阵转置,两个元素其实是关于对角线对称,那么对于一个对角线上的值,我们可以通过若干次转置使得他的顺序可以调整。只需要判断对角线上的值是否完全一致即可。

int mp1[555][555],mp2[555][555];
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>mp1[i][j];
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>mp2[i][j];
        }
    }
    vector<int>a[1111],b[1111];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            a[i+j].push_back(mp1[i][j]);
            b[i+j].push_back(mp2[i][j]);
        }
    }
    for(int i=2;i<=n+m;i++)sort(a[i].begin(),a[i].end()),sort(b[i].begin(),b[i].end());
    for(int i=2;i<=n+m;i++){
        if(a[i]!=b[i]){
            cout<<"NO\n";
            return 0;
        }
    }
    cout<<"YES\n";
    return 0;
}

D.Nastya Is Buying Lunch

题意:有n个人在排队,给出n个人的编号,你是队伍中最后一个人,给出k个关系,若u在v前面一个,则u,v可以交换位置,问你最多能前进多少距离。
题解:若你能够前进,则前面一个人必须能够和你交换位置,对这个过程进行模拟,从后往前找第一个可以和你交换的人,然后判断他能否到达你前面一个的位置。最多判断k次。

int pos[300500];
map<pair<int,int>,int>mp;
int main() 
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>pos[i];
    for(int i=1,u,v;i<=k;i++){
        cin>>u>>v;
        mp[make_pair(u,v)]=1;
    }
    int last=n;
    for(int i=n-1;i>=1;i--){
        int j;
        if(mp[make_pair(pos[i],pos[last])]){
            for(j=i;j<last;j++){
                if(mp[make_pair(pos[j],pos[j+1])])swap(pos[j],pos[j+1]);
                else break;
            }
            if(j==last)last--;
        }
    }
    cout<<n-last;
    return 0;
}

E.Nastya Hasn’t Written a Legend

题意:你有一个 a a a数组和 k k k数组。若 a i + 1 < a i + k i , a i + 1 = a i + k i a_{i+1}<a_i+k_i,a_{i+1}=a_i+k_i ai+1<ai+ki,ai+1=ai+ki
q q q次操作,一种问询问 [ l , r ] [l,r] [l,r] ∑ i = l r a i \sum_{i=l}^ra_i i=lrai,一种为, a k = a k + v a l a_k=a_k+val ak=ak+val
题解:对于加操作来说,若 y y y位置 a y > = a y − 1 + k y − 1 a_y>=a_{y-1}+k_{y-1} ay>=ay1+ky1,那么 a y a_y ay不会改变,因为 a y a_y ay不改变,后面的 a i a_i ai也不会改变。这个 y y y的位置是单调的,我们可以二分来找到 y y y
找到 y y y后,对于 [ x , y ] [x,y] [x,y]区间的 a i a_i ai都会改变, a x = a x + v a l , a x + 1 = a x + k x + v a l , a x + 2 = a x + k x + k x + 1 + v a l . . . a_x=a_x+val,a_{x+1}=a_x+k_x+val,a_{x+2}=a_{x}+k_x+k_{x+1}+val... ax=ax+val,ax+1=ax+kx+val,ax+2=ax+kx+kx+1+val...
那么对 [ l , r ] [l,r] [l,r]求和,则有 ∑ i = l r a i = ( y − x + 1 ) ∗ ( a [ x ] + v a l ) + ( y − x ) ∗ k x + ( y − x − 1 ) ∗ k x + 1 + . . . k y \sum_{i=l}^ra_i=(y-x+1)*(a[x]+val)+(y-x)*k_x+(y-x-1)*k_{x+1}+...k_y i=lrai=(yx+1)(a[x]+val)+(yx)kx+(yx1)kx+1+...ky
对于后面的一连串的累加我们可以通过前缀来O(1)计算。用b表示 k i k_i ki的前缀和,用c来表示b的前缀和。
那么后面的东西就等价于 c [ y ] − c [ x − 1 ] − ( y − x + 1 ) ∗ b [ x ] c[y]-c[x-1]-(y-x+1)*b[x] c[y]c[x1](yx+1)b[x]
那么 s u m = ( y − x + 1 ) ∗ ( a [ x ] + v a l − b [ x ] ) + c [ y ] − c [ x − 1 ] sum=(y-x+1)*(a[x]+val-b[x])+c[y]-c[x-1] sum=(yx+1)(a[x]+valb[x])+c[y]c[x1]
我们会发现 a [ x ] + v a l − b [ x ] a[x]+val-b[x] a[x]+valb[x]为一个定值,将这个值最为标记进行区间修改即可。( a x + 1 = a x + k x , b x + 1 = b x + k x a_{x+1}=a_x+k_x,b_{x+1}=b_x+k_x ax+1=ax+kx,bx+1=bx+kx)

struct node{
    ll sum,lazy;
    ll l,r;
}tree[maxn<<2];
ll a[maxn],b[maxn],c[maxn];
void build(int id,int l,int r){
    tree[id].l=l;tree[id].r=r;tree[id].lazy=-inf;
    if(l==r){
        tree[id].sum=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;
}
void change(int id,ll val){
    if(val==-inf)return ;
    int l=tree[id].l,r=tree[id].r;
    tree[id].sum=(ll)(r-l+1ll)*val+c[r]-c[l-1];
    tree[id].lazy=val;
    return;
}
void pushdown(int id){
    if(tree[id].lazy==-inf)return;
    change(id<<1,tree[id].lazy);
    change(id<<1|1,tree[id].lazy);
    tree[id].lazy=-inf;
    return;
}
void update(int id,int l,int r,int lx,int ly,ll val){
    if(l>=lx&&r<=ly){
        change(id,val);
        return;
    }
    int mid=(l+r)>>1;
    pushdown(id);
    if(mid>=lx)update(id<<1,l,mid,lx,ly,val);
    if(mid<ly)update(id<<1|1,mid+1,r,lx,ly,val);
    tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;
}
ll query(int id,int l,int r,int lx,int ly){
    if(l>=lx&&r<=ly){
        return tree[id].sum;
    }
    int mid=(l+r)>>1;
    pushdown(id);
    ll ans=0;
    if(mid>=lx)ans+=query(id<<1,l,mid,lx,ly);
    if(mid<ly)ans+=query(id<<1|1,mid+1,r,lx,ly);
    return ans;
}
int main() 
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=2;i<=n;i++)cin>>b[i],b[i]+=b[i-1];
    for(int i=2;i<=n;i++)c[i]=b[i]+c[i-1];
    build(1,1,n);
    ll q;
    cin>>q;
    string s;
    for(ll i=1,x,y;i<=q;i++){
        cin>>s>>x>>y;
        if(s=="+"){
            ll tmp=query(1,1,n,x,x);
            ll l=x,r=n;
            while(l<r){
                ll mid=(l+r+1)>>1;
                ll tmp1=query(1,1,n,mid,mid);
                if(tmp+y+b[mid]-b[x]>tmp1)l=mid;
                else r=mid-1;
            }
            update(1,1,n,x,l,tmp+y-b[x]);
        }
        else{
            cout<<query(1,1,n,x,y)<<"\n";
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值