AtCoder Beginner Contest 356

ABC356 A - Subsegment Reverse

题目传送门


代码(签到题)

#include <cstdio>
#include <cctype>
#include <bitset>
#include <algorithm>
using namespace std;
int n,a[111],l,r;
int main(){
    scanf("%d%d%d",&n,&l,&r);
    for (int i=1;i<=n;++i) a[i]=i;
    reverse(a+l,a+1+r);
    for (int i=1;i<=n;++i) printf("%d ",a[i]);
    return 0;
}

ABC356 B - Nutrients

题目传送门


代码(签到题)

#include <cstdio>
#include <cctype>
#include <bitset>
#include <algorithm>
using namespace std;
int n,a[111],m;
int main(){
    scanf("%d%d",&m,&n);
    for (int i=1;i<=n;++i) scanf("%d",&a[i]);
    for (int i=1;i<=m;++i)
    for (int j=1,x;j<=n;++j) scanf("%d",&x),a[j]-=x;
    for (int i=1;i<=n;++i)
    if (a[i]>0) return !printf("No");
    return !printf("Yes");
}

ABC356 C - Keys

题目传送门


分析

直接枚举真的钥匙的 \(2^n\) 种状态就可以了


代码

#include <cstdio>
#include <cctype>
#include <bitset>
#include <algorithm>
using namespace std;
int n,xo[40011],a[111],b[111],m,k,ans;
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<(1<<n);++i) xo[i]=xo[i&(i-1)]+1;
    for (int i=1;i<=m;++i){
        int j,x; char ch;
        for (scanf("%d",&j);j;--j) scanf("%d",&x),a[i]|=1<<(x-1);
        ch=getchar();
        while (ch!='o'&&ch!='x') ch=getchar();
        b[i]=(ch=='o');
    }
    for (int S=0;S<(1<<n);++S){
        int flag=1;
        for (int i=1;i<=m;++i)
            if ((xo[a[i]&S]>=k)^b[i]) flag=0;
        ans+=flag;
    }
    return !printf("%d",ans);
}

ABC356 D - Masked Popcount

题目传送门


分析

\(m\) 的每一位 \(1\) 进行拆位求解,如果 \(n\) 的这一位也为 \(1\)

那么 \(n\) 的最后几位都可以填 \(\leq n\) 的数,高位保持不变。

否则就让 \(n\) 的某个为 \(1\) 的高位填 \(0\),那么这一位填 \(1\),其它低位想填什么都可以。


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
long long n,m,ans;
int iut(){
    int ans=0; char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans;
}
int main(){
    scanf("%lld%lld",&n,&m);
    for (int i=0;i<60;++i)
    if ((m>>i)&1){
        if ((n>>i)&1) ans=(ans+n-((n>>i)<<i)+1)%998244353;
        for (int j=59;j>i;--j)
            if ((n>>j)&1) ans=(ans+(1ll<<(j-1)))%998244353;
    }
    return !printf("%lld",ans);
}

ABC356 E - Max/Min

题目传送门


分析

不妨枚举较小值,如果较大值与较小值相等那就是组合数,否则可以通过枚举倍数的方式,

因为此时在某段区间里商都是一样的,此时对次数求个前缀和预处理即可。


代码

#include <cstdio>
#include <cctype>
#include <bitset>
#include <algorithm>
using namespace std;
const int N=1000011;
int n,mx,c[N],s[N]; long long ans;
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;++i){
        int x; scanf("%d",&x);
        mx=max(mx,x),++c[x];
    }
    for (int i=1;i<=mx;++i) s[i]=s[i-1]+c[i];
    for (int i=1;i<=mx;++i) if (c[i])
    for (int j=i;j<=mx;j+=i){
        if (i==j) ans+=c[i]*(c[i]-1ll)/2;
        ans+=1ll*c[i]*(j/i)*(s[min(mx,j+i-1)]-s[j-(i!=j)]);
    }
    return !printf("%lld",ans);
}

ABC356 F - Distance Component Size Query

题目传送门


分析

维护两个平衡树,一个平衡树装入集合中的数,另一个装入连通块的左右端点,

再用动态开点的权值线段树维护,查询时找到连通块的左右端点查询个数。


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <set>
using namespace std;
typedef long long lll;
const lll INF=2333333333333333333ll;
const int N=200011; lll d,x,pre,nxt;
set<lll>K,F; set<lll>::iterator it;
int Q,root,tot,w[N<<6],ls[N<<6],rs[N<<6];
lll iut(){
    lll ans=0; char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans;
}
void print(int ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
void update(int &rt,lll l,lll r,lll x,int y){
    if (!rt) rt=++tot; w[rt]+=y;
    if (l==r) return;
    lll mid=(l+r)>>1;
    if (x<=mid) update(ls[rt],l,mid,x,y);
        else update(rs[rt],mid+1,r,x,y);
}
int query(int rt,lll l,lll r,lll x,lll y){
    if (!rt) return 0;
    if (l==x&&r==y) return w[rt];
    lll mid=(l+r)>>1;
    if (y<=mid) return query(ls[rt],l,mid,x,y);
    else if (x>mid) return query(rs[rt],mid+1,r,x,y);
        else return query(ls[rt],l,mid,x,mid)+query(rs[rt],mid+1,r,mid+1,y);
}
int main(){
    Q=iut(),d=iut();
    K.insert(-INF),K.insert(INF);
    F.insert(-INF),F.insert(INF);
    update(root,-INF,INF,-INF,1);
    update(root,-INF,INF,INF,1);
    for (int i=1;i<=Q;++i)
    if (iut()==2){
        x=iut(),it=F.lower_bound(x);
        nxt=*it,--it,pre=*it;
        print(query(root,-INF,INF,pre,nxt)-1),putchar(10);
    }else{
        x=iut(),it=K.lower_bound(x);
        if ((*it)==x){
            F.erase(x);
            ++it,nxt=*it,--it,--it,pre=*it;
            if (nxt-pre>d) F.insert(pre);
            K.erase(x),update(root,-INF,INF,x,-1);
        }else{
            nxt=*it,--it,pre=*it,F.erase(pre);
            if (nxt-x>d) F.insert(x);
            if (x-pre>d) F.insert(pre);
            K.insert(x),update(root,-INF,INF,x,1);
        }
    }
    return 0;
}

ABC356 G - Freestyle

题目传送门


分析

有一些姿势虽然能游更长,但更耗费体力,有些虽然不怎么耗费体力,但是游得不够久。

考虑对 (体力,距离) 维护上凸壳,其实答案很接近斜率,如果体力完全够用,

那么使用最后一个点,否则二分斜率的位置解二元一次方程即可。


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=200011;
struct Point{
    long long x,y;
    Point operator -(const Point &t)const{
        return (Point){x-t.x,y-t.y};
    }
}a[N];
int n,st[N],Top,mx;
int iut(){
    int ans=0,f=1; char c=getchar();
    while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans*f;
}
bool cmp(Point x,Point y){
    if (x.x!=y.x) return x.x<y.x;
    return x.y>y.y;
}
long long cj(Point x,Point y){
    return x.x*y.y-x.y*y.x;
}
int main(){
    n=iut();
    for (int i=1;i<=n;++i) a[i]=(Point){iut(),iut()};
    sort(a,a+1+n,cmp),Top=1;
    for (int i=1;i<=n;++i)
    if (a[i].x!=a[i-1].x){
        while (Top>1&&cj(a[st[Top]]-a[st[Top-1]],a[i]-a[st[Top-1]])>=0) --Top;
        st[++Top]=i;
    }
    for (int i=1;i<=Top;++i)
        if (mx<a[st[i]].y) mx=a[st[i]].y;
    while (Top&&a[st[Top]].y<mx) --Top;
    for (int Q=iut();Q;--Q){
        int x=iut(),y=iut();
        if (x*a[st[2]].y<y*a[st[2]].x){
            printf("-1\n");
            continue;
        }
        if (x*a[st[Top]].y>=y*a[st[Top]].x){
            printf("%.12Lf\n",(long double)y/a[st[Top]].y);
            continue;
        }
        int l=2,r=Top;
        while (l<r){
            int mid=(l+r+1)>>1;
            if (x*a[st[mid]].y>=y*a[st[mid]].x) l=mid;
                else r=mid-1;
        }
        printf("%.12Lf\n",(long double)cj((Point){x,y},a[st[l]]-a[st[l+1]])/cj(a[st[l+1]],a[st[l]]));
    }
    return 0;
}
posted @ 2024-09-01 01:20  lemondinosaur  阅读(14)  评论(0编辑  收藏  举报