ABC260

链接https://atcoder.jp/contests/abc260

阔别oi生涯2年,做康复训练,先从abc开始把

B

就按照不同的关键字三次排序就行了

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+11;
int n,x,y,z,cnt,ans[N];
bool is[N];
struct per{
	int a=0,b=0,tot=0,id;
}p[N];
bool cmp1(per t1,per t2){return t1.a>t2.a||(t1.a==t2.a&&t1.id<t2.id);}
bool cmp2(per t1,per t2){return t1.b>t2.b||(t1.b==t2.b&&t1.id<t2.id);}
bool cmp3(per t1,per t2){return t1.tot>t2.tot||(t1.tot==t2.tot&&t1.id<t2.id);}
int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int main(){
	n=read(),x=read(),y=read(),z=read();
	for(int i=1;i<=n;i++) p[i].id=i,p[i].a=read(),p[i].tot+=p[i].a;
	for(int i=1;i<=n;i++) p[i].b=read(),p[i].tot+=p[i].b;
	sort(p+1,p+n+1,cmp1);int st=0;
	while(x>0){if(!is[p[++st].id]){is[p[st].id]=1;ans[++cnt]=p[st].id;--x;}}
	st=0;sort(p+1,p+n+1,cmp2);
	while(y>0){if(!is[p[++st].id]){is[p[st].id]=1;ans[++cnt]=p[st].id;--y;}}
	st=0;sort(p+1,p+n+1,cmp3);
	while(z>0){if(!is[p[++st].id]){is[p[st].id]=1;ans[++cnt]=p[st].id;--z;}}
	sort(ans+1,ans+cnt+1);
	for(int i=1;i<=cnt;i++) printf("%d\n",ans[i]);
	return 0;
}

C

简单dp

#include<bits/stdc++.h>
using namespace std;
int n,x,y;
long long f[11][2];
int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int main(){
	n=read(),x=read(),y=read();
	f[1][1]=1;
	for(int i=2;i<=n;i++){
		f[i][1]+=f[i-1][0]+y*f[i-1][1];
		f[i][0]+=f[i-1][0]+x*f[i][1];
	}
	printf("%lld\n",f[n][0]);
	return 0;
}

D

数据结构,我一开始连nxt都没想到,还去整队列,思路已经堵塞了。。。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+11;
int n,k,p[N];
int ans[N],nxt[N],cnt[N];
set<int> h;
int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int main(){
	n=read(),k=read();
	memset(ans,-1,sizeof(ans));
	for(int i=1;i<=n;i++){
		p[i]=read();
		if(k==1){ans[p[i]]=i;continue;}
		auto it=h.upper_bound(p[i]);
		if(it==h.end()){
			h.insert(p[i]);
			++cnt[p[i]];
		}
		else{
			nxt[p[i]]=*it;
			cnt[p[i]]=cnt[*it]+1;
			h.erase(it);
			if(cnt[p[i]]>=k)
				for(int j=p[i];j;j=nxt[j]) ans[j]=i;
			else h.insert(p[i]);
		}
	}
    for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
	return 0;
}

E

由好序列的定义,我们可以得知一个性质,如果一个序列[l,r]是好的,那么对于所有涵盖了[l,r]的区间[i,j]来说,他们都是好的

我们枚举左右区间,若当前区间满足好,则++l,并计入答案,否则++r,这样子可以枚举出所有满足条件的最小区间

答案计算可以用差分实现

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+11;
int n,m,a[N],b[N],is[N],ans[N];
vector<int>h[N];
int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++){
        a[i]=read(),b[i]=read();
        h[a[i]].push_back(i);
        h[b[i]].push_back(i);
    }
    int l=1,r=0,cnt=0,flag=0;
    while(l<=m&&r<=m){
        if(!flag){
            ++r;
            for(auto it:h[r]){
                ++is[it];
                if(is[it]==1) ++cnt;
            }
            if(cnt==n) flag=1;
        }
        else{
            ans[r-l+1]++;
            ans[m-l+2]--;
            for(auto it:h[l]){
                --is[it];
                if(is[it]==0) --cnt;
            }++l;
            if(cnt<n) flag=0;
        }
    }
    for(int i=1;i<=m;i++){
        ans[i]+=ans[i-1];
        printf("%d ",ans[i]);
    }
	return 0;
}

下面是复杂度分析,可以看出枚举区间只需要2m次,而判断是否满足好,因为1~n每个数也只出现两次,所以是2n

时间复杂度O(M+N)

F

注意到他分成了两个independent set,那么如果出现了一个四元环一定是2个点来自V1,两个点来自V2,并且V1的两个点要与V2的两个都有边

注意到点集V2的范围只有3000,考虑数组\(f[i][j]\),记录与ij都有边的点,然后暴力枚举

#include<bits/stdc++.h>
using namespace std;
const int M=3e3+1;
const int N=3e5+1;
int s,t,m,f[M][M];
vector<int>h[N];
int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int main(){
    s=read(),t=read(),m=read();
    for(int i=1;i<=m;i++) h[read()].push_back(read()-s);
    for(int i=1;i<=s;i++)
        for(auto j:h[i])
            for(auto k:h[i]){
                if(j==k) continue;
                if(!f[j][k]) f[j][k]=i;
                else{
                    printf("%d %d %d %d",j+s,k+s,i,f[j][k]);
                    return 0;
                }
            }
    printf("-1");
	return 0;
}

你可能会想,这不是铁tle,然而我们对算法进行复杂度分析

我们可以发现,这个枚举过程,最多枚举\(C_{t}^2+1\)次,当我们枚举\(C_t^2\)次后,所有\(f[i][j]\)都已经有值了

posted @ 2022-07-22 15:26  DQY_dqy  阅读(89)  评论(0编辑  收藏  举报