zoukankan      html  css  js  c++  java
  • codechef november challenge 2020 division 2

    题解赛后发。
    最后一题没看懂题意就没做
    结果发现我第一次理解的题意是对的。。。。。。。
    感觉这次题目没有什么思维难度。
    ADADISH
    签到。

    #include<bits/stdc++.h>
    using namespace std;
    #define N 5010
    int n,T,a[N],f[N];
    int main(){
    	scanf("%d",&T);
    	while(T--){
    		int s=0;
    		memset(f,0,sizeof(f));
    		scanf("%d",&n);
    		for(int i=1;i<=n;i++){
    			scanf("%d",&a[i]);
    			s+=a[i];
    		}
    		f[0]=1;
    		for(int i=1;i<=n;i++)
    			for(int j=s;j>=a[i];j--)
    				f[j]|=f[j-a[i]];
    		int ans=1e9;
    		for(int i=1;i<=s;i++)
    			if(f[i])
    				ans=min(ans,max(s-i,i));
    		printf("%d
    ",ans);
    	}
    }
    

    RESTORE
    签到。

    #include<bits/stdc++.h>
    using namespace std;
    #define N 2000010
    int T,n,b[N],ct,p[N],vi[N],cv;
    int main(){
    	scanf("%d",&T);
    	for(int i=2;i<N;i++){
    		if(!vi[i])
    			p[++ct]=i;
    		for(int j=1;j<=ct&&p[j]*i<N;j++){
    			vi[i*p[j]]=1;
    			if(i%p[j]==0)
    				break;
    		}
    	}
    	while(T--){
    		cv=0;
    		scanf("%d",&n);
    		for(int i=1;i<=n;i++)
    			scanf("%d",&b[i]);
    		for(int i=1;i<=n;i++)
    			vi[i]=0;
    		for(int i=1;i<=n;i++){
    			if(!vi[b[i]])
    				vi[b[i]]=++cv;
    			printf("%d ",p[vi[b[i]]]);
    		}
    		puts("");
    	}
    }
    
    
    

    FEMA2
    把序列从堵住的格子劈开,使用两个set维护磁铁和铁块,贪心的选择距离最远的进行匹配。

    #include<bits/stdc++.h>
    using namespace std;
    #define N 500010
    int T,n,k,p[N],ans;
    char s[N];
    multiset<int>s1,s2;
    void gt(int x,int y){
    	p[x-1]=0;
    	for(int i=x;i<=y;i++){
    		p[i]=p[i-1];
    		if(s[i]==':')
    			p[i]++;
    	}
    	s1.clear();
    	s2.clear();
    	for(int i=x;i<=y;i++){
    		if(s[i]=='I'){
    			if(s1.empty()){
    				s2.insert(i+p[i]);
    				continue;
    			}
    			multiset<int>::iterator it=s1.upper_bound(i+p[i]-k-1);
    			if(it!=s1.end()){
    				s1.erase(it);
    				ans++;
    			}
    			else
    				s2.insert(i+p[i]);
    		}
    		else if(s[i]=='M'){
    			if(s2.empty()){
    				s1.insert(i+p[i]);
    				continue;
    			}
    			multiset<int>::iterator it=s2.upper_bound(i+p[i]-k-1);
    			if(it!=s2.end()){
    				s2.erase(it);
    				ans++;
    			}
    			else
    				s1.insert(i+p[i]);
    		}
    	}
    }
    int main(){
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d%d%s",&n,&k,s+1);
    		ans=0;
    		for(int i=1;i<=n;i++)
    			if(s[i]!='X'){
    				int j=i;
    				while(j<n&&s[j+1]!='X')
    					j++;
    				gt(i,j);
    				i=j;
    			}
    		for(int i=1;i<=n;i++)
    			p[i]=0;
    		printf("%d
    ",ans);
    	}
    }
    

    CNDYGAME
    按照1的位置分类讨论。
    这道简单题搞了我很久。。。。。

    #include<bits/stdc++.h>
    using namespace std;
    #define N 300010
    #define int long long
    #define mo 1000000007
    int T,a[N],s[N],b[N];
    signed main(){
    	scanf("%lld",&T);
    	while(T--){
    		int n,q;
    		scanf("%lld",&n);
    		int po=0;
    		for(int i=1;i<=n;i++)
    			scanf("%lld",&a[i]);
    		for(int i=1;i<=n;i++)
    			if(a[i]==1){
    				po=i;
    				break;
    			}
    		if(po==1){
    			scanf("%lld",&q);
    			while(q--){
    				int x,ans;
    				scanf("%lld",&x);
    				if(n!=1){
    					ans=x/n;
    					if(x%n!=0)
    						ans++;
    					if(x%n==1&&x!=1)
    						ans--;
    					printf("%lld
    ",ans%mo);
    				}
    				else
    					printf("%lld
    ",x%mo);
    			}
    		}
    		else if(po==n||!po){
    			for(int i=1;i<=n;i++){
    				if(i!=n){
    					if(a[i]%2==0){
    						s[i]=(s[i-1]+a[i])%mo;
    						b[i]=a[i];
    					}
    					else{
    						s[i]=(s[i-1]+a[i]-1)%mo;
    						b[i]=a[i]-1;
    					}	
    				}	
    				else{
    					if(a[i]%2==1){
    						s[i]=(s[i-1]+a[i])%mo;
    						b[i]=a[i];
    					}
    					else{
    						s[i]=(s[i-1]+a[i]-1)%mo;
    						b[i]=a[i]-1;
    					}
    				}
    			}
    			scanf("%lld",&q);
    			while(q--){
    				int x,ans;
    				scanf("%lld",&x);
    				ans=s[n]*((x/n)%mo)%mo;
    				x%=n;
    				if(!x){
    				    if(a[n]!=b[n])
    						printf("%lld
    ",(ans+1)%mo);
    					else
    						printf("%lld
    ",ans);
    				}
    				else{
    					ans=(ans+s[x])%mo;
    					if(a[x]!=b[x])
    						printf("%lld
    ",(ans+1)%mo);
    					else
    						printf("%lld
    ",ans);
    				}
    			}
    		}
    		else{
    			for(int i=1;i<=n;i++){
    				if(i+1==po){
    					if(a[i]%2==1){
    						s[i]=(s[i-1]+a[i])%mo;
    						b[i]=a[i];
    					}
    					else{
    						s[i]=(s[i-1]+a[i]-1)%mo;
    						b[i]=a[i]-1;
    					}
    				}
    				else{
    					if(i==po){
    						s[i]=s[i-1];
    						b[i]=0;
    					}
    					else if(i!=n){
    						if(a[i]%2==0){
    							s[i]=(s[i-1]+a[i])%mo;
    							b[i]=a[i];
    						}
    						else{
    							s[i]=(s[i-1]+a[i]-1)%mo;
    							b[i]=a[i]-1;
    						}
    					}
    					else{
    						if(a[i]%2==1){
    							s[i]=(s[i-1]+a[i])%mo;
    							b[i]=a[i];
    						}
    						else{
    							s[i]=(s[i-1]+a[i]-1)%mo;
    							b[i]=a[i]-1;
    						}
    					}
    				}
    			}
    			scanf("%lld",&q);
    			while(q--){
    				int x,ans;
    				scanf("%lld",&x);
    				ans=s[n]*((x/n)%mo)%mo;
    				x%=n;
    				if(!x){
    					if(a[n]!=b[n])
    						printf("%lld
    ",(ans+1)%mo);
    					else
    						printf("%lld
    ",ans);
    				}
    				else{
    					ans=(ans+s[x])%mo;
    					if(x==po){
    						if(a[x-1]%2==0)
    							ans=(ans+2)%mo;
    						printf("%lld
    ",ans);
    					}
    					else{
    						if(a[x]!=b[x])
    							printf("%lld
    ",(ans+1)%mo);
    						else
    							printf("%lld
    ",ans);
    					}
    				}
    			}
    		}
    		for(int i=1;i<=n+5;i++)
    			a[i]=s[i]=b[i]=0;
    	}
    }
    

    UNSQUERS
    某个原题的加强版。
    把一个点向它右边第一个>它的点连边,则形成了一棵树。
    在一次询问内把区间所有点标记。
    考虑扫描线,扫到i的时候处理以i为右端点的询问。
    注意到一个点一定和一个被标记的叶子节点连通(就是只能通过标记的点到达)。
    考虑维护一个点能够向上跳跳到标记点的最多次数(a),则答案就是a在区间[l,r]的最大值。
    如果把树dfs一下,则每次对答案的贡献就是个区间+,使用线段树维护。
    在线把线段树可持久化一下。

    #include<bits/stdc++.h>
    using namespace std;
    #define N 200010
    int n,m,a[N],bt[N],v[N*2],nxt[N*2],h[N],ec,ans[N],mn[N],rt[N];
    void add(int x,int y){v[++ec]=y;nxt[ec]=h[x];h[x]=ec;}
    void gt(int x,int y){for(;x;x-=x&-x)bt[x]=min(bt[x],y);}
    int q(int x){int r=1e9;for(;x<100010;x+=x&-x)r=min(r,bt[x]);return r;}
    struct tr{
    	int tg[N*30],s[N*30],lc[N*30],rc[N*30],ct;
    	void add(int &o,int p,int l,int r,int x,int y,int z){
    		o=++ct;
    		s[o]=s[p];
    		tg[o]=tg[p];
    		lc[o]=lc[p];
    		rc[o]=rc[p];
    		if(r<x||y<l)return;
    		if(x<=l&&r<=y){
    			tg[o]+=z;
    			s[o]+=z;
    			return;
    		}
    		int md=(l+r)/2;
    		add(lc[o],lc[p],l,md,x,y,z);
    		add(rc[o],rc[p],md+1,r,x,y,z);
    		s[o]=max(s[lc[o]],s[rc[o]])+tg[o];
    	}
    	int q(int o,int l,int r,int x,int y,int va){
    		if(r<x||y<l)return 0;
    		if(x<=l&&r<=y)return s[o]+va;
    		int md=(l+r)/2;
    		return max(q(lc[o],l,md,x,y,va+tg[o]),q(rc[o],md+1,r,x,y,va+tg[o]));
    	}
    }sv;
    void dfs(int x){
    	mn[x]=x;
    	for(int i=h[x];i;i=nxt[i]){
    		dfs(v[i]);
    		mn[x]=min(mn[x],mn[v[i]]);
    	}
    }
    int main(){
    	//freopen("exchange.in","r",stdin);
    	//freopen("exchange.out","w",stdout);
    	int t;
    	scanf("%d%d%d",&n,&m,&t);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	memset(bt,63,sizeof(bt));
    	n++;a[n]=100005;
    	for(int i=n;i>=1;i--){
    		int v=q(a[i]+1);
    		if(i!=n)add(v,i);
    		gt(a[i],i);
    	}
    	dfs(n);
    	int p=1;
    	for(int i=1;i<=n;i++)
    		sv.add(rt[i],rt[i-1],1,n,mn[i],i,1);
    	int la=0;
    	for(int i=1;i<=m;i++){
    		int l,r;
    		scanf("%d%d",&l,&r);
    		l=(l+t*la-1)%(n-1)+1;
    		r=(r+t*la-1)%(n-1)+1;
    		if(l>r)
    			swap(l,r);
    		printf("%d
    ",la=sv.q(rt[r],1,n,l,r,0));
    	}
    }
    

    SCALSUM
    显然可以树上莫队,但是时间很卡。
    考虑一种常数更小的方法。
    (s_i)为深度为(i)的点的个数。
    维护一个点(i)跳到上面第一次跳到(<sqrt{n},geq sqrt{n})的点(f_i,g_i)
    暴力跳(g),维护(s_{i,j,k})表示深度为(k)的点,(i,j)的贡献。
    然后(s_{i,j,k})能够通过(s_{i,j,l})(l)(k)上面第一个(s)(<sqrt{n})的点)轻松得来。

    #include<bits/stdc++.h>
    #define int unsigned int
    //#pragma GCC optimize(3)
    using namespace std;
    #define N 600010
    int n,q,w[N],v[N],nxt[N],h[N],ec,d[N],cc[N],id[N],ans[N],f[N],tp[600][600],nw[600][600],tt[N],ff[N],bs,g[N];
    void add(int x,int y){
    	v[++ec]=y;
    	nxt[ec]=h[x];
    	h[x]=ec;
    }
    struct no{
    	int x,y,id;
    };
    vector<no>vc[N];
    vector<int>dc[N];
    int rd(){
    	int x=0;
    	char c=getchar();
    	while(!isdigit(c))
    		c=getchar();
    	while(isdigit(c)){
    		x=x*10u+c-'0';
    		c=getchar();
    	}
    	return x;
    }
    void d1(int x,int fa){
    	dc[d[x]].push_back(x);
    	ff[x]=fa;
    	cc[d[x]]++;
    	for(int i=h[x];i;i=nxt[i])
    		if(v[i]!=fa){
    			d[v[i]]=d[x]+1;
    			d1(v[i],x);
    		}
    }
    void d2(int x,int fa){
    	for(int i=h[x];i;i=nxt[i])
    		if(v[i]!=fa){
    			if(cc[d[v[i]]]<=bs)
    				f[v[i]]=f[x];
    			else
    				f[v[i]]=v[i];
    			if(cc[d[v[i]]]>bs)
    				g[v[i]]=g[x];
    			else
    				g[v[i]]=v[i];
    			d2(v[i],x);
    		}
    }
    signed main(){
    	//freopen("r.in","r",stdin);
    	//freopen("w2.out","w",stdout);
    	n=rd();
    	q=rd();
    	for(int i=1;i<=n;i++)
    		w[i]=rd();
    	for(int i=1;i<n;i++){
    		int x=rd(),y=rd();
    		add(x,y);
    		add(y,x);
    	}
    	bs=sqrt(n);
    	g[1]=1;
    	d1(1,0);
    	d2(1,0);
    	for(int i=1;i<=q;i++){
    		int x=rd(),y=rd();
    		if(g[x])
    			vc[d[g[x]]].push_back((no){g[x],g[y],i});
    		x=f[x];
    		y=f[y];
    		while(x){
    			ans[i]+=w[x]*w[y];
    			x=f[ff[x]];
    			y=f[ff[y]];
    		}
    	}
    	for(int i=0;i<=n;i++)
    		if(cc[i]<=bs){
    			int ct=0,s=dc[i].size();
    			for(int j=0;j<s;j++){
    				tt[++ct]=dc[i][j];
    				id[dc[i][j]]=ct;
    			}
    			for(int j=1;j<=ct;j++)
    				for(int k=1;k<=ct;k++){
    					int a=tt[j],b=tt[k],c=g[ff[a]],d=g[ff[b]];
    					nw[id[a]][id[b]]=w[a]*w[b]+tp[id[c]][id[d]];
    				}
    			for(no x:vc[i])
    				ans[x.id]+=nw[id[x.x]][id[x.y]];
    			for(int j=1;j<=ct;j++)
    				for(int k=1;k<=ct;k++){
    					tp[j][k]=nw[j][k];
    					nw[j][k]=0;
    				}
    		}
    	for(int i=1;i<=q;i++)
    		printf("%u
    ",ans[i]);
    }
    

    CHEFSSM
    (sum E(p)*i=sum E(p>=i)),其中(p)为一个局面能够转到正确位置的最小步数。
    实际上我们要求的是对于(0leq xleq p)(x)((2x+v_1)(2x+v_2)...(2x+v_n))的和。
    把这个式子用分治(fft)展开,发现我们要求若干个底数相同但是幂数不同的自然数幂和。
    使用伯努利数计算。求自然数幂和的公式也可以用卷积优化。

    #include<bits/stdc++.h>
    using namespace std;
    #define mo 998244353
    #define N 300010
    #define int long long
    #define ll unsigned long long
    #define pl vector<int>
    int qp(int x,int y){
    	int r=1;
    	for(;y;y>>=1,x=1ll*x*x%mo)
    		if(y&1)r=1ll*r*x%mo;
    	return r;
    }
    int n,k,rev[N],v,c,le,w[N];
    ll b[N];
    void deb(pl x){
    	for(int i:x)cout<<i<<' ';
    	puts("");
    }
    void init(int n){
    	v=1;
    	le=0;
    	while(v<n)le++,v*=2;
    	for(signed i=0;i<v;i++)
    		rev[i]=(rev[i>>1]>>1)|((i&1)<<(le-1));
    	int g=qp(3,(mo-1)/v);
    	w[v/2]=1;
    	for(int i=v/2+1;i<v;i++)
    		w[i]=1ull*w[i-1]*g%mo;
    	for(signed i=v/2-1;~i;i--)
    		w[i]=w[i*2];
    }
    void fft(int v,pl &a,int t){
    	static unsigned long long b[N];
    	int s=le-__builtin_ctz(v);
       	for(int i=0;i<v;i++)
       		b[rev[i]>>s]=a[i];
    	int c=0;
    	w[0]=1;
        for(signed i=1;i<v;i*=2,c++)
        	for(signed r=i*2,j=0;j<v;j+=r)
                for(signed k=0;k<i;k++){
                   	int tx=b[j+i+k]*w[k+i]%mo;
                	b[j+i+k]=b[j+k]+mo-tx;
                	b[j+k]+=tx;
                }
        for(int i=0;i<v;i++)
        	a[i]=b[i]%mo;
        if(t==0)return;
        int iv=qp(v,mo-2);
        for(signed i=0;i<v;i++)
        	a[i]=1ull*a[i]*iv%mo;
        a.resize(v);
        reverse(a.begin()+1,a.end());
    }
    pl operator *(pl x,pl y){
    	int s=x.size()+y.size()-1;
    	init(s);
    	x.resize(v);
    	y.resize(v);
    	fft(v,x,0);
    	fft(v,y,0);
    	for(int i=0;i<v;i++)
    		x[i]=x[i]*y[i]%mo;
    	fft(v,x,1);
    	x.resize(s);
    	return x;
    }
    void inv(int n,pl &b,pl &a){
    	if(n==1){
    		b[0]=qp(a[0],mo-2);
    		return;
    	}
    	inv((n+1)/2,b,a);
        static pl c;
    	init(n*2);
    	c.resize(v);
    	b.resize(v);
        for(int i=0;i<n;i++)
    		c[i]=a[i];
        fft(v,c,0);
        //deb(c);
    	fft(v,b,0);
    	//deb(b);
        for(int i=0;i<v;i++)
        	b[i]=1ll*(2ll-1ll*c[i]*b[i]%mo+mo)%mo*b[i]%mo;
        //deb(b);
        fft(v,b,1);
        //deb(b);
       	b.resize(n);
       	//deb(b);
    }
    void ad(pl &x,pl y,int l){
    	x.resize(max((int)x.size(),(int)y.size()+l));
    	for(int i=0;i<y.size();i++)
    		x[i+l]=(x[i+l]+y[i])%mo;
    }
    pl operator +(pl x,pl y){
    	ad(x,y,0);
    	return x;
    }
    pl iv(pl x){
    	pl y;
    	int n=x.size();
    	y.resize(n);
    	inv(n,y,x);
    	y.resize(n);
    	return y;
    }
    int a[N],T,B[N],va[N];
    pl fz(int l,int r){
    	if(l==r){
    		pl va;
    		va.resize(2);
    		va[1]=mo-2;
    		va[0]=a[l]+1;
    		return va;
    	}
    	int md=(l+r)/2;
    	return fz(l,md)*fz(md+1,r);
    }
    void cal(int v,int x){
    	pl a,b;
    	a.resize(x+2);
    	b.resize(x+2);
    	va[0]=v;
    	int vv=1;
    	for(int i=0;i<=x+1;i++){
    		a[i]=B[i]*qp(vv,mo-2)%mo;
    		vv=vv*(i+1)%mo;
    	}
    	vv=1;
    	for(int i=0;i<=x+1;i++){
    		b[i]=qp(v+1,i+1)*qp(vv,mo-2)%mo;
    		vv=vv*(i+2)%mo;
    	}
    	a=a*b;
    	vv=1;
    	for(int i=1;i<=x;i++){
    		va[i]=vv*a[i]%mo;
    		vv=vv*(i+1)%mo;
    	}
    	va[0]=v;
    }
    signed main(){
    	scanf("%lld",&T);
    	while(T--){
    		scanf("%lld",&n);
    		int mn=1e18,vv=1;
    		for(int i=1;i<=n;i++){
    			scanf("%lld",&a[i]);
    			mn=min(mn,a[i]);
    			va[i]=a[i];
    			vv=vv*(a[i]+1)%mo;
    		}
    		pl y;
    		y.resize(n+1);
    		int x=1;
    		for(int i=0;i<=n;i++){
    			x=x*(i+1)%mo;
    			y[i]=qp(x,mo-2)%mo;
    		}
    		y=iv(y);
    		x=1;
    		for(int i=0;i<=n;i++){
    			B[i]=y[i]*x%mo;
    			x=x*(i+1)%mo;
    		}
    		B[0]=1;
    		pl z=fz(1,n);
    		cal((mn+1)/2,n);
    		int ans=0;
    		for(int i=0;i<=n;i++)
    			ans=(ans+va[i]*z[i]%mo)%mo;
    		printf("%lld
    ",ans*qp(vv,mo-2)%mo);
    	}
    }
    

    RB2CNF
    显然我们求出一个合法的染色方案后就是个经典的二元关系网络流。
    然后求出合法的染色方案可以使用二分图染色。

  • 相关阅读:
    凤凰网CEO刘爽称鄙视微博连说20个屁示不齿
    科技创业网站
    梦想,在路上
    小本创业
    rails relevent
    MBA = married but available
    把UTF8编码转换为GB2312编码[转]
    FSFS和VDFS存储方式的区别
    如何让phpmyadmin输入密码再进入
    dede后台登陆后一片空白的解决办法汇总
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/13971632.html
Copyright © 2011-2022 走看看