Educational Codeforces Round 62
A
模拟......
#include<cstdio>
#include<algorithm>
using namespace std;
int a[10005],n,ans;
int main(){
scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&a[i]);
int i=1;
while(i<=n){
int now=a[i],j=i;ans++;
while(j<n&&now>j) j++,now=max(now,a[j]);
i=j+1;
}
printf("%d\n",ans);return 0;
}
B
考虑保留前端的\(>\),后端的\(<\)的最优解即可.
#include<cstdio>
#include<algorithm>
using namespace std;
int n,T,ans;
char s[105];
void work(){
scanf("%d",&n);scanf("%s",s+1);ans=n;
int i=1;while(i<=n&&s[i]!='>') i++;ans=min(ans,i-1);
//printf("%d\n",i);
i=n;while(i>=1&&s[i]!='<') i--;ans=min(ans,n-i);//printf("%d\n",i);
printf("%d\n",ans);
}
int main(){
scanf("%d",&T);while(T--) work();
return 0;
}
C
排序后用堆维护前K大.
#include<cstdio>
#include<queue>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=300005;
int n,K;
struct jz{
int x,y;
bool operator<(const jz &b)const{return y>b.y;}
}a[maxn];
int top;
LL ans,num;
priority_queue<int,vector<int>,greater<int> >heap;
void put(int x){num+=x;top++;heap.push(x);}
void get(){top--;num-=heap.top();heap.pop();}
int main(){
scanf("%d%d",&n,&K);
for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
sort(a+1,a+1+n);
for (int i=1;i<=n;i++){
put(a[i].x);
if (top>K) get();
ans=max(ans,num*a[i].y);
}
printf("%lld\n",ans);
return 0;
}
D
每次都是从\(1\)开始相邻两个剖分显然是最优解.
#include<cstdio>
#include<queue>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=300005;
int n,K;
LL ans,num;
int main(){
scanf("%d%d",&n);
for (int i=3;i<=n;i++) ans+=(i-1)*i;
printf("%lld\n",ans);
return 0;
}
E
显然只要满足\(a[i]!=a[i-2]\)即可.按位置奇偶分开考虑,那么就是相邻的数不相同.
考虑暴力的DP,\(f[i][j]\)做完前\(i\)个位置第\(i\)个位置的数是\(j\),转移显然.
然后发现转移的时候类似一个区间乘区间加的操作,直接线段树维护即可.
好像与题解有所不同,因为乘法的时候有负数,所以被坑了...
#include<queue>
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=200005,tt=998244353;
int n,c[maxn],K;
struct jz{
int L,R;
LL tag1,tag2,w;
}a[4*maxn];
LL ans;
void build(int x,int L,int R){
a[x].L=L;a[x].R=R;a[x].tag1=1;a[x].tag2=0;
if (L==R){a[x].w=0;return;}
int mid=L+R>>1;
build(x*2,L,mid);build(x*2+1,mid+1,R);
a[x].w=(a[x*2].w+a[x*2+1].w)%tt;
}
void Pushdown(int x){
if (a[x].L==a[x].R) return;
LL tag1=a[x].tag1,tag2=a[x].tag2;a[x].tag1=1;a[x].tag2=0;
a[x*2].w=(a[x*2].w*tag1+tag2*(a[x*2].R-a[x*2].L+1))%tt;
a[x*2+1].w=(a[x*2+1].w*tag1+tag2*(a[x*2+1].R-a[x*2+1].L+1))%tt;
a[x*2].tag1=(a[x*2].tag1*tag1)%tt;
a[x*2+1].tag1=(a[x*2+1].tag1*tag1)%tt;
a[x*2].tag2=(a[x*2].tag2*tag1+tag2)%tt;
a[x*2+1].tag2=(a[x*2+1].tag2*tag1+tag2)%tt;
}
void change(int x,int L,int R,int c,int p){
Pushdown(x);
if (a[x].L==L&&a[x].R==R){
a[x].tag1=(a[x].tag1*c)%tt;
a[x].tag2=(a[x].tag2*c%tt+p)%tt;
a[x].w=(a[x].w*c%tt+(LL)(a[x].R-a[x].L+1)*p)%tt;
return;
}
int mid=a[x].L+a[x].R>>1;
if (R<=mid) change(x*2,L,R,c,p);
else if (L>mid) change(x*2+1,L,R,c,p);
else{change(x*2,L,mid,c,p);change(x*2+1,mid+1,R,c,p);}
a[x].w=(a[x*2].w+a[x*2+1].w)%tt;
}
int query(int x,int L,int R){
Pushdown(x);
if (a[x].L==L&&a[x].R==R) return (a[x].w+tt)%tt;
int mid=a[x].L+a[x].R>>1;
if (R<=mid) return query(x*2,L,R);
else if (L>mid) return query(x*2+1,L,R);
else return (query(x*2,L,mid)+query(x*2+1,mid+1,R))%tt;
}
int main(){
scanf("%d%d",&n,&K);
for (int i=1;i<=n;i++) scanf("%d",&c[i]);ans=1;
build(1,1,K);
if (c[1]!=-1) change(1,c[1],c[1],1,1);else change(1,1,K,1,1);
for (int i=3;i<=n;i+=2){
int sum=query(1,1,K);
if (c[i]!=-1){
if (c[i]>1) change(1,1,c[i]-1,0,0);
if (c[i]<K) change(1,c[i]+1,K,0,0);
change(1,c[i],c[i],-1,sum);
}else change(1,1,K,-1,sum);
}
ans=ans*query(1,1,K)%tt;
build(1,1,K);
if (c[2]!=-1) change(1,c[2],c[2],1,1);else change(1,1,K,1,1);
for (int i=4;i<=n;i+=2){
int sum=query(1,1,K);
if (c[i]!=-1){
if (c[i]>1) change(1,1,c[i]-1,0,0);
if (c[i]<K) change(1,c[i]+1,K,0,0);
change(1,c[i],c[i],-1,sum);
}else change(1,1,K,-1,sum);
}
ans=ans*query(1,1,K)%tt;
printf("%lld\n",ans);
return 0;
}
F
感觉比较显然...
把行和列看成点,加入/删除点就是加入/删除一条边,最后答案显然就是所有联通中行数*列数的和.
直接线段树分治+并查集维护就可以了.
#include<map>
#include<cstdio>
#include<vector>
#include<algorithm>
#define LL long long
#define ls (x<<1)
#define rs ((x<<1)+1)
using namespace std;
const int maxn=600005,N=3e5;
struct jz{int x,y,d;}a[maxn];
struct node{
int x,y;
node(int x=0,int y=0):x(x),y(y){}
}S[maxn];
map<LL,int> vis;
vector<int> que[maxn*4];
int n,top,f[maxn],sx[maxn],sy[maxn];
LL ans;
inline int _read(){
int num=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();
return num;
}
void add(int x,int l,int r,int L,int R,int y){
if (l==L&&r==R){que[x].push_back(y);return;}
int mid=l+(r-l>>1);
if (R<=mid) add(ls,l,mid,L,R,y);else
if (L>mid) add(rs,mid+1,r,L,R,y);else
add(ls,l,mid,L,mid,y),add(rs,mid+1,r,mid+1,R,y);
}
int get(int x){if (f[x]==x) return x;return get(f[x]);}
void add(int x,int w){ans+=(LL)sx[x]*sy[x]*w;}
void merge(int x,int y){
x=get(x);y=get(y);if (x==y) return;
if (sx[x]+sy[x]<sx[y]+sy[y]) swap(x,y);
S[++top]=node(x,y);add(x,-1);add(y,-1);
f[y]=x;sx[x]+=sx[y];sy[x]+=sy[y];add(x,1);
}
void Back(int x){
while(top!=x){
int x=S[top].x,y=S[top].y;add(x,-1);
f[y]=y;sx[x]-=sx[y];sy[x]-=sy[y];add(x,1);add(y,1);top--;
}
}
void work(int x,int l,int r){
int tim=top;
for (int i=0;i<que[x].size();i++) merge(a[que[x][i]].x,a[que[x][i]].y+N);
if (l==r){
printf("%lld ",ans);
if (a[l+1].d) add(1,1,n,l+1,a[l+1].d,l+1);
Back(tim);return;
}int mid=l+(r-l>>1);
work(ls,l,mid);work(rs,mid+1,r);Back(tim);
}
int main(){
n=_read();for (int i=1;i<=n;i++){
a[i].x=_read(),a[i].y=_read();
LL w=(LL)a[i].x*N+a[i].y;
if (!vis[w]) vis[w]=i;else a[vis[w]].d=i-1,vis[w]=0;
}
for (int i=n;i>=1;i--){
LL w=(LL)a[i].x*N+a[i].y;
if (vis[w]) a[i].d=n,vis[w]=0;
}
for (int i=1;i<=2*N;i++) f[i]=i,sx[i]=(i<=N),sy[i]=(i>N);
//for (int i=1;i<=n;i++) printf("%d\n",a[i].d);
if (a[1].d) add(1,1,n,1,a[1].d,1);work(1,1,n);
return 0;
}
G
咕咕咕...