AtCoder Beginner Contest 355

ABC355 A - Who Ate the Cake?

题目传送门


代码(签到题)

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
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;
}
int main(){
    int n=iut(),m=iut();
    if (n==m) printf("-1");
        else printf("%d",6-n-m);
    return 0;
}

ABC355 B - Piano 2

题目传送门


代码(签到题)

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m,a[211],b[211];
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;
}
int main(){
    n=iut(),m=iut();
    for (int i=1;i<=n;++i) a[i]=iut();
    for (int i=1;i<=m;++i) b[i]=iut();
    sort(a+1,a+1+n),sort(b+1,b+1+m);
    int I=1,J=1,flag=0;
    while (I<=n&&J<=m)
    if (a[I]<b[J]){
        if (flag) return !printf("Yes");
        flag=1,++I;
    }else ++J,flag=0;
    if (I<n) return !printf("Yes");
        else printf("No");
    return 0;
}

ABC355 C - Bingo 2

题目传送门


代码(签到题)

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=2011;
int n,T,row[N],column[N],zhu,fu;
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;
}
int main(){
    n=iut(),T=iut();
    for (int i=1;i<=T;++i){
        int t=iut(),x=(t-1)/n+1,y=t-(x-1)*n;
        ++row[x],++column[y];
        if (x==y) ++zhu;
        if (x+y==n+1) ++fu;
        if (row[x]==n||column[y]==n||zhu==n||fu==n)
            return !printf("%d",i);
    }
    return !printf("-1");
}

ABC355 D - Intersecting Intervals

题目传送门


分析

考虑容斥,用总数减去不相交的区间数,不相交的区间数可以用树状数组实现


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1000011;
long long ans;
int n,m,l[N],r[N],b[N],c[2][N];
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;
}
void update(int x,int z){
    for (;x<=m;x+=-x&x) ++c[z][x];
}
int query(int x,int z){
    int ans=0;
    for (;x;x-=-x&x) ans+=c[z][x];
    return ans;
}
int main(){
    n=iut();
    for (int i=1;i<=n;++i){
        l[i]=iut(),r[i]=iut();
        b[++m]=l[i],b[++m]=r[i];
    }
    sort(b+1,b+1+m),m=unique(b+1,b+1+m)-b-1;
    ans=n*(n-1ll)/2;
    for (int i=1;i<=n;++i){
        l[i]=lower_bound(b+1,b+1+m,l[i])-b;
        r[i]=lower_bound(b+1,b+1+m,r[i])-b;
        ans-=query(l[i]-1,0)+i-1-query(r[i],1);
        update(r[i],0),update(l[i],1);
    }
    return !printf("%lld",ans);
}

ABC355 E - Guess the Sum

题目传送门


分析

实际上,连续和的求值可以变成两个前缀和相减的形式,而 \((L,R)\) 区间最多只有 \(n2^n\) 个,

要求询问次数最少,询问实际上只与端点有关,询问次数实际上是最短路,那么使用 BFS 找到最短路的路径,利用路径完成交互。


代码

#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
const int N=300011; queue<int>q;
int pre[N],lg[N],n,L,R,ans,z;
void doit(int x){
    if (pre[x]==pre[L]) return;
    if (pre[x]<x) cout<<"? "<<lg[x-pre[x]]<<' '<<pre[x]/(x-pre[x])<<endl,cin>>z,ans=(ans+z)%100;
        else cout<<"? "<<lg[pre[x]-x]<<' '<<x/(pre[x]-x)<<endl,cin>>z,ans=(ans+100-z)%100;
    doit(pre[x]);
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>L>>R,++R,lg[0]=pre[0]=-1;
    for (int i=1;i<=(1<<n);++i) pre[i]=-1,lg[i]=lg[i>>1]+1;
    pre[L]=(1<<n)+1,q.push(L);
    while (!q.empty()){
        int x=q.front(); q.pop();
        if (x==R){
            doit(R);
            cout<<"! "<<ans<<endl;
            return 0;
        }
        if (!x){
            for (int z=1;z<pre[L];z<<=1)
                if (pre[z]==-1) q.push(z),pre[z]=x;
            continue;
        }
        for (int z=-x&x;z;z>>=1){
            if (x+z<pre[L]&&pre[x+z]==-1) q.push(x+z),pre[x+z]=x;
            if (pre[x-z]==-1) q.push(x-z),pre[x-z]=x;
        }
    }
    return 0;
}

ABC355 F - MST Query

题目传送门


分析

边权最多 \(10\) 种,一开始是一棵树,那么一开始的答案就是所有边权之和,

那么开 \(10\) 个并查集,第 \(i\) 个并查集中只装入边权大于等于 \(i\) 的边,

对于每个询问,将边丢入相应的并查集内,如果该边构成了新的生成树,说明原边被替换了,

假设原边的边权为 \(x\),新边的边权为 \(y\),那么在第 \(y\sim x-1\) 个并查集中均添加了新边,

减去 \(x-y\) 的贡献,所以就是添加一个新边,就将答案减一。


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=200011;
int n,Q,f[10][N],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;
}
void print(int ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
int getf(int j,int u){return f[j][u]==u?u:f[j][u]=getf(j,f[j][u]);}
int main(){
    n=iut(),Q=iut();
    for (int j=1;j<10;++j)
        for (int i=1;i<=n;++i) f[j][i]=i;
    for (int i=1;i<n;++i){
        int x=iut(),y=iut(),z=iut();
        ans+=z;
        for (int j=z;j<10;++j)
            f[j][getf(j,x)]=f[j][getf(j,y)];
    }
    for (int i=1;i<=Q;++i){
        int x=iut(),y=iut(),z=iut();
        for (int j=z;j<10;++j)
        if (getf(j,x)!=getf(j,y))
            f[j][getf(j,x)]=f[j][getf(j,y)],--ans;
        else break;
        print(ans),putchar(10);
    }
    return 0;
}

ABC355 G - Baseball

题目传送门


分析

乘上了 \(\sum_{i=1}^nP_i\),不妨令第 \(0\) 个位置和第 \(n+1\) 个位置必选但在最小值时不可用。

那么题目就转换成了恰好选择 \(k\) 个点分成 \(k+1\) 段,对于相邻的选择点 \(x,y\),使得 \(\sum\sum_{i=x+1}^{y-1}\min\{i-x,y-i\}\times P_i\) 最小

\(dp[i][j]\) 表示前 \(i\) 个位置分成了 \(j\) 段的最小值,第二维由于式子满足四边形不等式,可利用决策单调性进行优化。

即使优化后仍是于事无补,考虑利用 WQS 二分斜率强加贡献,那么就变成了 \(O(n\log n\log k)\),貌似斜率的二分上界要上到 long long


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=50011; int n,m,head,tail,K[N],a[N],f[N],q[N];
typedef long long lll; lll dp[N],s[N],S[N],ans;
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
lll calc(int l,int r){
	if (l>r) return 0;
	if (l==1&&r==n) return 1e12;
	if (l==1) return (s[r]-s[l-1])*(r+1)-(S[r]-S[l-1]);
	if (r==n) return (S[r]-S[l-1])-(s[r]-s[l-1])*(l-1);
	int mid=(l+r)>>1;
	return (S[mid]-S[l-1])-(s[mid]-s[l-1])*(l-1)+(s[r]-s[mid])*(r+1)-(S[r]-S[mid]);
}
int ef(int X,int Y){
	int l=Y+1,r=n+2;
	while (l<r){
	    int mid=(l+r)>>1;
		if (dp[X]+calc(X+1,mid-1)>=dp[Y]+calc(Y+1,mid-1)) r=mid;
		    else l=mid+1;
	}
	return l;
}
void doit(lll mid){
	head=tail=0;
	for (int i=1;i<=n+1;++i){
		while (head<tail&&K[head]<=i) ++head;
		dp[i]=dp[q[head]]+calc(q[head]+1,i-1)+mid,f[i]=f[q[head]]+1;
		while (head<tail&&K[tail-1]>=ef(q[tail],i)) --tail;
		K[tail]=ef(q[tail],i),q[++tail]=i;
	}
}
int main(){
	n=iut(); m=iut()+1;
	for (int i=1;i<=n;++i) a[i]=iut();
	for (int i=1;i<=n;++i) s[i]=s[i-1]+a[i],S[i]=S[i-1]+1ll*a[i]*i;
	lll l=0,r=623623623617ll;
	while (l<r){
		lll mid=(l+r+1)>>1; doit(mid);
		if (f[n+1]>=m) ans=dp[n+1]-m*mid,l=mid;
		    else r=mid-1;
	}
	return !printf("%lld",ans);
}

posted @ 2024-10-07 22:05  lemondinosaur  阅读(14)  评论(0编辑  收藏  举报