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]\)都已经有值了