• 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
    ",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
    ",i);
    	i=n;while(i>=1&&s[i]!='<') i--;ans=min(ans,n-i);//printf("%d
    ",i);
    	printf("%d
    ",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
    ",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
    ",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
    ",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
    ",a[i].d);
    	if (a[1].d) add(1,1,n,1,a[1].d,1);work(1,1,n);
    	return 0;
    }
    

    G

    咕咕咕...

  • 相关阅读:
    SQL中join的用法
    SQL中sysname数据类型的含义(转)
    MVC-Razor视图
    GridView用法
    常见的23种设计模式
    协程
    Kotlin学习
    数据绑定库和MVVM
    LiveData
    函数式编程
  • 原文地址:https://www.cnblogs.com/CHNJZ/p/10635548.html
Copyright © 2020-2023  润新知