AtCoder Beginner Contest 136

A

题意

水杯1有AmL的容量,且已装了BmL的水。水杯2有CmL的水。问水杯2最少留多少水?

思路

模拟。水杯2可向水杯1转移max(C,(A-B)),所以最少留max(0,C-(A-B))

#include<bits/stdc++.h>
using namespace std;
int a,b,c; 

int main(){
    scanf("%d%d%d",&a,&b,&c);
    printf("%d",max(0,c-(a-b)));
}

B

题意

求1-n中位数为奇数的数字的数量

思路

模拟。计算每个奇数位在<=n的情况下可取的数

 

#include<bits/stdc++.h>
using namespace std;
int n,now=1,ans;

int main(){
    scanf("%d",&n);
    for (int i=1;i<=5;i++){        
        if (i&1) ans+=min(n,now*10-1)-(now-1);
        now*=10;
        if (n<now) break;
    }
    printf("%d\n",ans);
}

 

C

题意

对于每个Hi执行-1或不变,问可否形成不递减序列

思路

因为要求不递减,操作又只能减,所以我们要求靠后的Hi尽可能大。逆向循环,看可否满足条件

#include<bits/stdc++.h>
using namespace std;
#define N (100010)
int n,h[N];

int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&h[i]);
    for (int i=n-1;i>=1;i--){
        if (h[i]<=h[i+1]) continue;
        else if (h[i]==h[i+1]+1) --h[i];
        else{printf("No"); return 0;}
    }
    printf("Yes");
}

D

题意

1-n的每个点上都标有'L'或'R',最初每个点上都有一个小孩。执行以下操作10^100次:

如果该点上标有'L',则小孩向左移;如果该点上标有'R',则小孩向右移。

数据保证点1上为'L',点n上为'R'。

思路

模拟。由于操作次数远大于n,所以小孩毕汇聚于某个'R''L'交接处[不断向左向右],而10^100次显然是偶数,只需判断小孩走偶数次是在'R'还是'L'上即可

 

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define M (1000000007)
#define N (100010)
int ans[N];
char a[N];

int main(){
    scanf("%s",a+1); int n=strlen(a+1);
    int l=1;
    while (l<=n){
        int r1=l;
        while (a[r1+1]=='R') ++r1;
        int r2=r1+1;
        while (a[r2+1]=='L') ++r2;
        for (int i=l;i<=r1;i++){
            if ((r1-i)&1) ++ans[r1+1];
            else ++ans[r1];
        }
        for (int i=r1+1;i<=r2;i++){
            if ((i-r1)&1) ++ans[r1+1];
            else ++ans[r1];
        }
        l=r2+1;
    }
    for (int i=1;i<=n;i++) printf("%d ",ans[i]);
}

 

E

题意

执行以下操作[次数0~k次]:选取i与j(i≠j),将a[i]+1,a[j]-1;

求操作完毕后序列a的最大公约数

思路

 

无论执行几次,序列a的总和都是不变的,所以GCD*x=∑a[i](1<=i<=n) [x∈Z]

所以答案必然是∑a[i]的因子

枚举∑a[i]的因子,一部分的数减小,一部分的数增大,看操作次数是否<=k

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define M (1000000007)
#define N (510)
int n,k,a[N],sum,son[30000],cha[N];

void solve(int x){
    for (int i=1;i*i<=x;i++) if (x%i==0){
        son[++son[0]]=i;
        if (x/i!=i) son[++son[0]]=x/i;
    }
}

bool check(int x){
    int cnt=0,have=k;
    for (int i=1;i<=n;i++){
        int t=a[i]%x;
        if (t==0) continue;
        cha[++cnt]=t;
    }
    sort(cha+1,cha+1+cnt);
    int l=1,r=cnt;
    while (l<r){
        int t=min(cha[l],x-cha[r]);
        if (have<t) return 0;
        have-=t; 
        cha[l]-=t; if (!cha[l]) ++l;
        cha[r]+=t; if (cha[r]==x) --r;
    }
    return 1;
}

int main(){
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]),sum+=a[i];
    solve(sum); sort(son+1,son+1+son[0]);
    for (int i=son[0];i>=1;i--){
        if (check(son[i])){
            printf("%d",son[i]);
            return 0;
        }
    }
}

F

题意

求∑F[T] [T是S集合非空子集] [F[T]:T中min-x,min-y,max-x,max-y所形成的矩阵可涵盖S集合中的点的数目]

思路

容斥+树状数组。先假设每个点都可被每个集合覆盖,再减去x都比当前点小/大的点,y都比当前点小/大的点,再加回多减的集合[x,y都在a[i]一侧的点]

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define M (998244353)
#define N (200010)
struct data{
    int x,y;
}a[N];
int n,ans,pow2[N]={1};
struct tree{
    int a[N];
    void clear(){memset(a,0,sizeof(a));}
    void update(int x){
        for (int i=x;i<=n;i+=i&-i) ++a[i];
    }
    int query(int x){
        int res=0;
        for (int i=x;i;i-=i&-i) res+=a[i];
        return res;
    }
}tr;

bool cmpx(data o1,data o2){return o1.x<o2.x;}

bool cmpy(data o1,data o2){return o1.y<o2.y;}

int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
    for (int i=1;i<=n+1;i++) pow2[i]=pow2[i-1]*2%M;
    ans=1ll*n*(pow2[n]-1)%M;//假设每个点都出现在所有集合中 
    sort(a+1,a+1+n,cmpx);
    for (int i=1;i<=n;i++){//减去所有构成元素的x都比a[i].x小/大的集合 
        ans=(ans-(pow2[i-1]-1)+M)%M;//<x
        ans=(ans-(pow2[n-i]-1)+M)%M;//>x
        a[i].x=i;
    } 
    sort(a+1,a+1+n,cmpy);
    for (int i=1;i<=n;i++){//减去所有构成元素的y都比a[i].y小/大的集合 
        ans=(ans-(pow2[i-1]-1)+M)%M;//<y
        ans=(ans-(pow2[n-i]-1)+M)%M;//>y
        a[i].y=i;
    }
    for (int i=1;i<=n;i++){//加上y<a[i].y且x都比a[i].x小/大的集合 
        int t=tr.query(a[i].x-1);
        ans=(ans+(pow2[t]-1))%M;//<x <y
        ans=(ans+(pow2[i-1-t]-1))%M;//>x <y
        tr.update(a[i].x);
    } 
    tr.clear();
    for (int i=n;i>=1;i--){//加上y>a[i].y且x都比a[i].x小/大的集合
        int t=tr.query(a[i].x);
        ans=(ans+(pow2[n-i-t]-1))%M;//>x >y
        ans=(ans+(pow2[t]-1))%M;//<x >y
        tr.update(a[i].x);
    }
    printf("%d",(ans+M)%M);
}
//容斥 

转载于:https://www.cnblogs.com/zhangjiayu/p/11303692.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值