模拟题大集合

其实是懒得开新文章了

2021-09-14 20:52:16 星期二

亿吨夸克玩字符串

题解,清楚!
2021-09-14 20_59_17屏幕截图.png
但是这里我并没有记忆化,可以通过枚举距离来dp,
第一维是左端点,第二维是答案串长度,第三维枚举dp长度,第四维枚举dp左端点,第五维枚举k,
发现答案串每个字母个数要和总串成比例,并且开头末尾的字母就是总串的字母,可以加个小剪枝。
好像会慢。

Code



#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("string.in","r",stdin);freopen("string.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=210;
	int lens,len,hv[N],co,dp[N],cnt[N],ans[N],bs;
	int f[N][N];
	char s[N];bool vis[N],fl;
	inline int gcd(int a,int b){return b?gcd(b,a%b):a;}
	inline short main(){
		file();
		int T=read();
		while(T--){
			F(i,1,co)vis[hv[i]]=0,cnt[hv[i]]=0,dp[hv[i]]=0;
			co=0;fl=0;
			scanf("%s",s+1);
			lens=strlen(s+1);
			F(i,1,lens){if(!vis[s[i]])vis[s[i]]=1,hv[++co]=s[i];cnt[s[i]]++;}
			int g=cnt[hv[1]];
			F(i,2,co)g=gcd(cnt[hv[i]],g);
			len=lens/g;
			ans[0]=0x7fffffff;
			F(st,1,lens){
				for(int i=len;i<=lens;i+=len){
					if(i>ans[0])break;
					int ed=st+i-1;
					bs=lens/i;bool flg=1;
					F(l,st,ed)dp[s[l]]=0;
					F(l,st,ed)dp[s[l]]++;
					F(l,st,ed)
						if(cnt[s[l]]!=dp[s[l]]*bs){
							flg=0;break;
						}
					if(s[st]!=s[1]||s[ed]!=s[lens])flg=0;
					if(!flg)continue;
					F(l,1,lens)f[l][l]=(s[l]==s[st]);
					F(l,2,lens){
						F(k,1,lens){
							//k是左端点,l是长度,o是右端点,t是几个len,i是len,st是答案左端点
							if(k+l-1>lens)break;
							int o=k+l-1;
							f[k][o]=0;
							f[k][o]|=f[k][o-1]&(s[o]==s[st+(o-k)%i]);
							if(f[k][o])continue;
							F(t,1,(o-k+1)/i){
								if(o-t*i<k)break;
								f[k][o]|=f[k][o-t*i]&f[o-t*i+1][o];
								if(f[k][o])break;
							}
						}
					}
					if(f[1][lens]){
						if(ans[0]>i){
							ans[0]=i;
							F(l,1,i)ans[l]=s[st+l-1];
						}else{
							F(l,1,i){
								if(ans[l]==s[st+l-1])continue;
								if(ans[l]>s[st+l-1])
									F(o,1,i)ans[o]=s[st+o-1];
								break;
							}
						}
					}
				}
			}
			F(i,1,ans[0])pf("%c",ans[i]);pn();
		}
		return 0;
	}
}
signed main(){return EMT::main();}

计数

题解,清楚!
2021-09-14 20_57_31屏幕截图.png
通过题解所述,根据m个要求更新每个值的lr数组,第一维枚举点,第二维枚举size,第三维枚举k即可。

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("count.in","r",stdin);freopen("count.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=410,mod=1e9+7;
	int l[N],r[N],n,m,f[N][N];
	inline short main(){
		file();
		int T=read();
		while(T--){
			n=read(),m=read();
			F(i,1,n)l[i]=0,r[i]=n-i+1;
			memset(f,0,sizeof(f));
			F(i,1,m){
				int a=read(),b=read();
				if(a>b){
					a^=b^=a^=b;
					l[a]=max(l[a],b-a);
				}else r[a]=min(r[a],b-a-1);
			}
			F(i,1,n+1)f[i][0]=1;
			D(i,n,1)F(j,1,n)F(k,l[i],r[i])if(k<j)f[i][j]+=1ll*f[i+1][k]*f[i+1+k][j-1-k]%mod,f[i][j]-=f[i][j]>=mod?mod:0;
			pi(f[1][n]);pn();
		}
		return 0;
	}
}
signed main(){return EMT::main();}

亿吨夸克和售货机

题解,清楚!
2021-09-14 20_53_14屏幕截图.png
2021-09-14 20_56_21屏幕截图.png
只将每个点的最大值和次大值(收益)记录下来,另外将最大值对应的点对连边,把不亏的能买的先都买到1个,然后整个图会分为i几个联通块,链的显然除了左端点都可以买到,环的就先都买下来,看哪个点最大与次大差值最小,减去这个差值,相当于用了次大放弃最大的边,如果有自环就特判一下,把差值改成0即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("goods.in","r",stdin);freopen("goods.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=1e5+1;
	int head[N],co,n,maxval[N],secval[N],in[N],out[N],f[N],c[N],d[N],a[N],mincost;
	struct node{int next,to;}e[N];ll ans;bool vis[N];
	inline void add(int next,int to){e[++co]=(node){head[next],to};head[next]=co;}
	inline void dfs(int k){
		vis[k]=1;
		for(register int i=head[k];i;i=e[i].next)
			ans+=maxval[e[i].to],dfs(e[i].to);
	}
	inline void Dfs(int k){
		if(vis[k])return;
		vis[k]=1;ans+=maxval[k];mincost=min(mincost,maxval[k]-secval[k]);
		for(register int i=head[k];i;i=e[i].next)
			if(e[i].to!=k)Dfs(e[i].to);else{
				mincost=0;return;
			}
	}
	inline short main(){
		file();
		;;;;;
		n=read();
		F(i,1,n)f[i]=read(),c[i]=read(),d[i]=read(),a[i]=read();
		F(i,1,n){
			int val=d[f[i]]-c[i];
			if(val<=0)continue;
			if(val>=maxval[f[i]])secval[f[i]]=maxval[f[i]],maxval[f[i]]=val;
			else if(val>=secval[f[i]])secval[f[i]]=val;
		}
		F(i,1,n){
			int val=d[f[i]]-c[i];
			if(val<=0)continue;
			if(maxval[f[i]]==val&&!in[f[i]])
				out[i]++,in[f[i]]++,add(i,f[i]);
		}
		F(i,1,n)
			if(maxval[i])
				ans+=1ll*(a[i]-1)*maxval[i];
		F(i,1,n)if(!vis[i]&&!in[i])dfs(i);
		F(i,1,n)if(!vis[i]&&in[i]==1&&out[i]==1)mincost=0x7fffffff,Dfs(i),ans-=mincost;
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

2021-09-13 16:07:18 星期一

由于数据最高的树高度只有25,所以可以qj数据点用动态开点线段树暴力水过

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	int tot;const int N=3e5+10;
	int lz[N*40],val[N*40],ls[N*40],rs[N*40];
	struct seg{
		inline void down(int p){
			if(lz[p]){
				if(!ls[p])ls[p]=++tot;
				if(!rs[p])rs[p]=++tot;
				lz[ls[p]]+=lz[p];
				lz[rs[p]]+=lz[p];
				val[ls[p]]+=lz[p];
				val[rs[p]]+=lz[p];
				lz[p]=0;
			}
		}
		inline void change(int &p,int l,int r,int ql,int qr,int v){
			if(!p)p=++tot;
			if(l>=ql&&r<=qr){
				lz[p]+=v;
				val[p]+=v;
				return;
			}int mid=(l+r)>>1;down(p);
			if(qr<=mid)change(ls[p],l,mid,ql,qr,v);
			else if(ql>mid)change(rs[p],mid+1,r,ql,qr,v);
			else change(ls[p],l,mid,ql,mid,v),change(rs[p],mid+1,r,mid+1,qr,v);
		}
		inline int ask(int p,int l,int r,int x){
			if(!p)return 0;
			if(l==r)return val[p];
			int mid=(l+r)>>1;down(p);
			if(x<=mid)return ask(ls[p],l,mid,x);
			else return ask(rs[p],mid+1,r,x);
		}
	}segm[N];
	int n,q,dfn[N],last[N],deep[N],head[N],co,ti,mxdep[N],rt[N];
	struct node{int next,to;}e[N<<1];
	inline void add(int next,int to){e[++co]=(node){head[next],to};head[next]=co;}
	inline void dfs(int k,int fa){
		dfn[k]=++ti;mxdep[k]=deep[k];
		for(register int i=head[k],j;i;i=e[i].next){
			if((j=e[i].to)==fa)continue;
			deep[j]=deep[k]+1;dfs(j,k);
			mxdep[k]=max(mxdep[k],mxdep[j]);
		}last[k]=ti;
	}
	inline short main(){
		n=read(),q=read();
		F(i,1,n-1){
			int x=read(),y=read();
			add(x,y);add(y,x);
		}dfs(1,0);
		while(q--){
			int opt=read();
			if(opt==1){
				int v=read(),x=read(),y=read(),z=read();
				int l=dfn[v],r=last[v],fin=mxdep[v],now=deep[v]+y;
				while(now<=fin){
					// pi(now);pi(l);pi(r);pn();
					segm[now].change(rt[now],1,n,l,r,z);
					now+=x;
				}
			}else{
				int x=read();//pi(deep[x]);pn();
				pi(segm[deep[x]].ask(rt[deep[x]],1,n,dfn[x])),pn();
			}
		}
		return 0;
	}
}
signed main(){return EMT::main();}

路径

由于数据水,所以可以用点分治水过。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e6+10,mod=998244353,inf=1e9;bool vis[N];
	int siz[N],son[N],sum[N],head[N],co,mx,size,rt,n,k,cnt[N],dp[N],pf[N],mx1,mx2,dis[N];
	struct node{int next,to;}e[N<<1];
	inline void add(int next,int to){e[++co]=(node){head[next],to};head[next]=co;}
	inline void getrt(int k,int fa){
		siz[k]=1;son[k]=0;
		for(register int i=head[k],j;i;i=e[i].next){
			if((j=e[i].to)==fa||vis[j])continue;
			getrt(j,k);siz[k]+=siz[j];
			son[k]=max(son[k],siz[j]);
		}son[k]=max(son[k],size-siz[k]);
		if(son[k]<mx)mx=son[k],rt=k;
	}int ans;
	inline int ksm(int a,int b){
		int ans=1;
		while(b){
			if(b&1)ans=1ll*a*ans%mod;
			a=1ll*a*a%mod;
			b>>=1;
		}return ans;
	}
	inline void getdis(int k,int fa){
		dp[dis[k]]++;mx1=max(mx1,dis[k]);
		for(register int i=head[k],j;i;i=e[i].next){
			if(vis[j=e[i].to]||j==fa)continue;
			dis[j]=dis[k]+1;getdis(j,k);
		}
	}
	inline void calc(int k){
		mx2=0;cnt[0]=1;
		for(register int i=head[k],j;i;i=e[i].next){
			if(vis[j=e[i].to])continue;
			dis[j]=1;mx1=0;getdis(j,k);
			F(l,0,mx2)F(o,1,mx1)ans+=1ll*pf[l+o]*cnt[l]%mod*dp[o]%mod,ans-=ans>=mod?mod:0;
			mx2=max(mx2,mx1);F(l,1,mx1)cnt[l]+=dp[l],dp[l]=0;
		}F(i,1,mx2)cnt[i]=0;
	}
	inline void dfs(int k){
		vis[k]=1;calc(k);
		for(register int i=head[k],j;i;i=e[i].next){
			if(vis[j=e[i].to])continue;
			size=siz[j],mx=inf,rt=0;
			getrt(j,k);dfs(rt);
		}
	}
	inline short main(){
		n=read(),k=read();
		F(i,1,n)pf[i]=ksm(i,k);
		F(i,1,n-1){
			int x=read(),y=read();
			add(x,y),add(y,x);
		}mx=inf,size=n;getrt(1,0);dfs(rt);
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

异或

发现第i位的1每\(2^i\)个数就有1的贡献,于是就出来了。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	ll ans,n;
	inline short main(){
		n=read();
		for(ll i=1;i<=n;i<<=1)
			ans+=n/i;
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

赌神

按比例把现在有的筹码分配到各种颜色上即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e6+10,mod=998244353;
	int n,jc[N],x[N],sumx,mulx;
	inline int ksm(int a,int b){
		int ans=1;
		while(b){
			if(b&1)ans=1ll*a*ans%mod;
			b>>=1;
			a=1ll*a*a%mod;
		}return ans;
	}
	inline short main(){
		n=read();mulx=jc[0]=1;
		F(i,1,n)x[i]=read(),sumx+=x[i];
		F(i,1,sumx)jc[i]=1ll*jc[i-1]*i%mod;
		int ans=ksm(n,sumx);
		F(i,1,n)mulx=1ll*mulx*jc[x[i]]%mod;
		int inv=1ll*jc[sumx]*ksm(mulx,mod-2)%mod;
		pi(1ll*ans*ksm(inv,mod-2)%mod);
		return 0;
	}
}
signed main(){return EMT::main();}

2021-09-12 19:44:27 星期日
改不出第四题的屑来写题解了

茅山道术

\(f_i\)表示到i的方案数,那么如果i的颜色出现过\(f_i=f_{i-1}+f_{last}\)否则\(f_i=f_{i-1}\)

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("magic.in","r",stdin);freopen("magic.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e6+10,mod=1e9+7;
	int n,c[N],last[N],f[N];
	inline short main(){
		file();
		n=read();
		F(i,1,n)c[i]=read();
		f[1]=1;last[c[1]]=1;
		F(i,2,n){
			if(!last[c[i]])f[i]=f[i-1];
			else{
				f[i]=(f[i-1]+(i-last[c[i]]>1)*f[last[c[i]]])%mod;
			}last[c[i]]=i;
		}pi(f[n]);
		return 0;
	}
}
signed main(){return EMT::main();}

泰拳警告

把p看成\(p+2\)场里能平\(p\)场,然后算出来总场数一除就行,考试脑抽没想到直接\(2^i\)除二就是\(\sum\limits_{j=(n-i)/2}^{n-i}C_{n-i}^{j}\),后面想出来了就简单了。

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("fight.in","r",stdin);freopen("fight.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int mod=998244353,N=3e6+10;
	inline int ksm(int a,int b){
		int ans=1;
		while(b){
			if(b&1)ans=1ll*ans*a%mod;
			b>>=1;
			a=1ll*a*a%mod;
		}return ans;
	}int n,p,jc[N],inv[N],ans,p2,invp;
	inline int C(int n,int m){
		return 1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;
	}
	int ksmp2[N],ksminvp[N],ksm2[N];
	inline short main(){
		file();
		n=read(),p=read();jc[0]=1;
		F(i,1,n)jc[i]=1ll*jc[i-1]*i%mod;
		inv[0]=inv[1]=1;
		inv[n]=ksm(jc[n],mod-2);
		D(i,n-1,2)inv[i]=1ll*inv[i+1]*(i+1)%mod;
		invp=ksm(p+2,mod-2);p2=1ll*p*invp%mod;
		ksmp2[0]=1;
		F(i,1,n)ksmp2[i]=1ll*ksmp2[i-1]*p2%mod;
		ksminvp[0]=1;
		F(i,1,n)ksminvp[i]=1ll*ksminvp[i-1]*invp%mod;
		ksm2[0]=1;
		F(i,1,n)ksm2[i]=1ll*ksm2[i-1]*2%mod;
		F(i,0,n-1){
			int base=1ll*C(n,i)*(i+1)%mod*ksmp2[i]%mod*ksminvp[n-i]%mod;
			/*F(j,(n-i)/2+1,n-i){
				ans+=1ll*C(n-i,j)*base%mod;
				ans-=ans>=mod?mod:0;
			}*/
			if((n-i)&1){
				ans+=1ll*ksm2[n-i-1]*base%mod;
			}else{
				ans+=1ll*((ksm2[n-i]-C(n-i,(n-i)>>1)+mod)%mod)*inv[2]%mod*base%mod;
			}ans-=ans>=mod?mod:0;
		}
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

万猪拱塔

题解说得很清楚了...以权值为下标维护区间最小值、个数、以及l之和,枚举r,注意用hash存权时边界问题,调了好久...感谢熠神。

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("pig.in","r",stdin);freopen("pig.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=6e5+10,mod=998244353;
	struct seg{
		int val[N<<2],cnt[N<<2],suml[N<<2],lz[N<<2];
		inline void up(int p){
			if(val[p<<1]<val[p<<1|1]){
				cnt[p]=cnt[p<<1];
				suml[p]=suml[p<<1];
				val[p]=val[p<<1];
			}else if(val[p<<1]>val[p<<1|1]){
				cnt[p]=cnt[p<<1|1];
				suml[p]=suml[p<<1|1];
				val[p]=val[p<<1|1];
			}else{
				cnt[p]=cnt[p<<1|1]+cnt[p<<1];
				suml[p]=suml[p<<1|1]+suml[p<<1];
				suml[p]-=suml[p]>=mod?mod:0;
				val[p]=val[p<<1|1];
			}
		}
		inline void build(int p,int l,int r){
			if(l==r)return val[p]=1e9,suml[p]=l,cnt[p]=1,void();
			int mid=(l+r)>>1;
			build(p<<1,l,mid);build(p<<1|1,mid+1,r);
			up(p);
		}
		inline void down(int p){
			if(lz[p]){
				val[p<<1]+=lz[p];
				val[p<<1|1]+=lz[p];
				lz[p<<1]+=lz[p];
				lz[p<<1|1]+=lz[p];
				lz[p]=0;
			}
		}
		inline void change(int p,int l,int r,int ql,int qr,int v){
			if(l>=ql&&r<=qr){
				val[p]+=v;
				lz[p]+=v;
				return;
			}int mid=(l+r)>>1;down(p);
			if(qr<=mid)change(p<<1,l,mid,ql,qr,v);
			else if(ql>mid)change(p<<1|1,mid+1,r,ql,qr,v);
			else change(p<<1,l,mid,ql,mid,v),change(p<<1|1,mid+1,r,mid+1,qr,v);
			up(p);
		}
		inline void to(int p,int l,int r,int x){
			if(l==r)return val[p]=4,void();
			int mid=(l+r)>>1;down(p);
			if(x<=mid)to(p<<1,l,mid,x);
			else to(p<<1|1,mid+1,r,x);
			up(p);
		}
	}segm;
	int n,m,w[N],ans;
	struct pt{int x,y,val;friend bool operator <(pt a,pt b){return a.val<b.val;}}p[N],dp[10],now[10];
	inline short main(){
		file();
		n=read(),m=read();
		F(i,1,n)F(j,1,m)w[i*(m+1)+j]=read(),p[w[i*(m+1)+j]]=(pt){i,j,0};
		int x,y;segm.build(1,1,n*m);
		F(i,1,n*m){
			x=p[i].x,y=p[i].y;
			dp[1]={x-1,y-1,0},dp[2]={x,y-1,0},dp[3]={x+1,y-1,0},dp[4]={x-1,y,0},
			dp[5]={x+1,y,0},dp[6]={x-1,y+1,0},dp[7]={x,y+1,0},dp[8]={x+1,y+1,0};
			F(j,1,8)dp[j].val=w[dp[j].x*(m+1)+dp[j].y];
			//124.
			int cnt=1,val=1;now[1].val=0;
			if(dp[1].val&&dp[1].val<=i)now[++cnt]=dp[1];
			if(dp[2].val&&dp[2].val<=i)now[++cnt]=dp[2];
			if(dp[4].val&&dp[4].val<=i)now[++cnt]=dp[4];
			std::sort(now+1,now+cnt+1);
			now[cnt+1].val=i;
			while(cnt)segm.change(1,1,n*m,now[cnt].val+1,now[cnt+1].val,val),cnt--,val=-val;
			//235.
			cnt=1,val=1;now[1].val=0;
			if(dp[2].val&&dp[2].val<=i)now[++cnt]=dp[2];
			if(dp[3].val&&dp[3].val<=i)now[++cnt]=dp[3];
			if(dp[5].val&&dp[5].val<=i)now[++cnt]=dp[5];
			std::sort(now+1,now+cnt+1);
			now[cnt+1].val=i;
			while(cnt)segm.change(1,1,n*m,now[cnt].val+1,now[cnt+1].val,val),cnt--,val=-val;
			//467.
			cnt=1,val=1;now[1].val=0;
			if(dp[4].val&&dp[4].val<=i)now[++cnt]=dp[4];
			if(dp[6].val&&dp[6].val<=i)now[++cnt]=dp[6];
			if(dp[7].val&&dp[7].val<=i)now[++cnt]=dp[7];
			std::sort(now+1,now+cnt+1);
			now[cnt+1].val=i;
			while(cnt)segm.change(1,1,n*m,now[cnt].val+1,now[cnt+1].val,val),cnt--,val=-val;
			//578.
			cnt=1,val=1;now[1].val=0;
			if(dp[5].val&&dp[5].val<=i)now[++cnt]=dp[5];
			if(dp[7].val&&dp[7].val<=i)now[++cnt]=dp[7];
			if(dp[8].val&&dp[8].val<=i)now[++cnt]=dp[8];
			std::sort(now+1,now+cnt+1);
			now[cnt+1].val=i;
			while(cnt)segm.change(1,1,n*m,now[cnt].val+1,now[cnt+1].val,val),cnt--,val=-val;
			segm.to(1,1,n*m,i);
			if(segm.val[1]==4)ans+=1ll*segm.cnt[1]*(i+1)%mod-segm.suml[1],ans+=ans<0?mod:(ans>=mod?-mod:0);
		}pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

2021-09-10 12:04:57 星期五

第负一题

感恩的心,感谢土哥

考虑分治优化统计答案,对于区间 [l,r]
计算所有经过其中点的区间对答案的贡献
那么只需考虑接口处是否选的情况下,向左/右选到某个位置的最大价值
设 fl[0/1][i][0/1] 表示在 mid 是/否选的情况下,从 [i,mid] 中选,i 是/否选的方案数,右边的 fr[0/1][i][0/1] 定义类似
那么合并有 f(i,j)=max(fl[0][i][0/1]+fr[0][j][0/1],fl[1][i][0/1]+fr[0][j][0/1],fl[0][i][0/1]+fr[1][j][0/1])
第三维 0/1 的选择取 max 即可,所以以下省略了
等价于 f(i,j)=fl[0][i]+fr[0][j]+max(max(fl[1][i]−fl[0][i],0),max(fr[1][j]−fr[0][j],0))
就可以拆开贡献,对于后面的 max,把左右的候选差值分别排序后双指针即可——土哥

这里我没有用双指针(其实也差不多),正常dp考虑贡献,fl[0][i]+fr[0][j]可以直接提出来,max一个用前缀和一个直接乘即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline ll max(ll a,ll b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=2e5+10,inf=1e9,mod=998244353;
	int n,a[N];ll ans,fl[N][2][2],fr[N][2][2],L[N][2],R[N][2],Ld[N],Rd[N],sum[N];
	inline void solve(int l,int r){
		if(l==r)return ans=(ans+a[l])%mod,void();
		int mid=(l+r)>>1;
		solve(l,mid);solve(mid+1,r);
		fl[mid][0][1]=-inf;fl[mid][1][0]=-inf;
		fr[mid+1][0][1]=fr[mid+1][1][0]=-inf;
		fl[mid][1][1]=a[mid];fl[mid][0][0]=0;
		fr[mid+1][1][1]=a[mid+1];fr[mid+1][0][0]=0;
		L[mid][0]=0;L[mid][1]=a[mid];
		Ld[mid]=a[mid];Rd[mid+1]=a[mid+1];
		R[mid+1][0]=0;R[mid+1][1]=a[mid+1];
		D(i,mid-1,l){
			fl[i][0][1]=fl[i+1][0][0]+a[i];
			fl[i][1][1]=fl[i+1][1][0]+a[i];
			fl[i][0][0]=max(fl[i+1][0][1],fl[i+1][0][0]);
			fl[i][1][0]=max(fl[i+1][1][0],fl[i+1][1][1]);
			L[i][0]=max(fl[i][0][1],fl[i][0][0]);
			L[i][1]=max(fl[i][1][1],fl[i][1][0]);
			Ld[i]=max(L[i][1]-L[i][0],0);
			(ans+=1ll*L[i][0]*(r-mid)%mod)%=mod;
		}
		F(i,mid+2,r){
			fr[i][0][1]=fr[i-1][0][0]+a[i];
			fr[i][1][1]=fr[i-1][1][0]+a[i];
			fr[i][0][0]=max(fr[i-1][0][1],fr[i-1][0][0]);
			fr[i][1][0]=max(fr[i-1][1][1],fr[i-1][1][0]);
			R[i][0]=max(fr[i][0][1],fr[i][0][0]);
			R[i][1]=max(fr[i][1][1],fr[i][1][0]);
			Rd[i]=max(R[i][1]-R[i][0],0);
			(ans+=1ll*R[i][0]*(mid-l+1)%mod)%=mod;
		}
		std::sort(Ld+l,Ld+mid+1);std::sort(Rd+mid+1,Rd+r+1);
		sum[mid]=0;
		F(i,mid+1,r)sum[i]=sum[i-1]+Rd[i];
		int p=r;
		D(lk,mid,l){
			while(Ld[lk]<=Rd[p]&&p>=mid+1)p--;
			(ans+=1ll*Ld[lk]*(p-mid)%mod)%=mod;
			(ans+=sum[r]-sum[p])%=mod;
		}
	}
	inline short main(){
		file();n=read();
		F(i,1,n)a[i]=read();
		solve(1,n);pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

第负二题

第一维枚举时间,第二维枚举行,n2过百万不是问题(逃

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=5e6+10,mod=998244353;
	int l[N],r[N],ll[N],rr[N],n,L,X,Y,f[N],minl,maxr;
	typedef unsigned long long u64;bool vis[N];
	u64 A,B;
	inline u64 readd(){u64 x=0;char ch=getchar();while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x;}
	u64 xorshift128p(u64 &A, u64 &B) { 
		u64 T = A, S = B; 
		A = S; 
		T ^= T << 23; 
		T ^= T >> 17; 
		T ^= S ^ (S >> 26); 
		B = T; 
		return T + S; 
	} 
	void gen(int n, int L, int X, int Y, u64 A, u64 B, int l[], int r[]) { 
		for (int i = 1; i <= n; i ++) { 
			l[i] = xorshift128p(A, B) % L + X; 
			r[i] = xorshift128p(A, B) % L + Y; 
			if (l[i] > r[i]) std::swap(l[i], r[i]); 
		} 
	}
	inline int ksm(int a,int b){
		int ans=1;
		while(b){
			if(b&1)ans=1ll*a*ans%mod;
			a=1ll*a*a%mod;
			b>>=1;
		}return ans;
	}
	inline short main(){
		n=read(),L=read(),X=read(),Y=read(),A=readd(),B=readd();
		gen(n,L,X,Y,A,B,ll,rr);
		minl=1e9;
		F(i,1,n)minl=min(minl,ll[i]);
		F(i,1,n)ll[i]=ll[i]-minl+1,rr[i]=rr[i]-minl+1,maxr=max(maxr,rr[i]);
		int cnt=0;
		F(stp,1,maxr){
			if(cnt==n)break;
			F(i,1,n)if(!vis[i])l[i]=ll[i],r[i]=rr[i];
			F(i,1,n){
				if(vis[i])continue;
				if(l[i]>r[i]&&!vis[i]){
					cnt++;vis[i]=1;
					f[i]=stp-1;
				}
				ll[i+1]=max(ll[i+1],l[i]);ll[i-1]=max(ll[i-1],l[i]);
				rr[i+1]=min(rr[i+1],r[i]);rr[i-1]=min(rr[i-1],r[i]);
				ll[i]=max(ll[i],l[i]+1);  rr[i]=min(rr[i],r[i]-1);
			}
			if(stp==1){
				ll[1]=ll[n]=5,rr[1]=rr[n]=4;
			}
		}
		int ans=0;
		F(i,1,n)(ans+=1ll*ksm(3,i-1)*f[i]%mod)%=mod;
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

2021-09-10 20:21:14 星期五
被精心构造的“随机"数据卡掉了...(zero4399不讲wood
bu hui zuo le
改 不 动 了

第零题

见注释

Code
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=2e5+10;
	int fa[N][22],deep[N],die[N][22];ll pre[N];
	int n,K,head[N],co;
	struct node{
		int next,to,w;
	}e[N<<1];
	inline void add(int next,int to,int w){e[++co]=(node){head[next],to,w};head[next]=co;}
	inline int getfa(int x,int k){//求k级父亲
		int now=x;
		D(i,20,0)if((1<<i)<=k)now=fa[now][i],k-=(1<<i);
		return now;
	}
	inline void dfs(int k,int f){
		int l=1,r=deep[k],ans=-1;
		//二分出k点以上哪个点到这个点的权值和正好>=k,即die[k][0]
		while(l<=r){
			int mid=(l+r)>>1;
			int x=getfa(k,mid);
			if(pre[k]-pre[x]>=K)ans=mid,r=mid-1;
			else l=mid+1;
		}if(ans!=-1)die[k][0]=getfa(k,ans);else die[k][0]=-1;//找不到就为-1
		//更新倍增数组
		if(ans!=-1)F(i,1,20)if((1<<i)<=deep[k])die[k][i]=die[die[k][i-1]][i-1];else break;
		for(register int i=head[k],j;i;i=e[i].next){
			j=e[i].to;if(j==f)continue;
			deep[j]=deep[k]+1;
			fa[j][0]=k;pre[j]=pre[k]+e[i].w;
			//pre用于权值前缀和,fa是正常倍增数组
			F(i,1,20)if((1<<i)<=deep[j])fa[j][i]=fa[fa[j][i-1]][i-1];else break;
			dfs(j,k);
		}
	}
	inline int getlca(int a,int b){
		if(deep[a]<deep[b])std::swap(a,b);
		D(i,20,0)if((1<<i)<=deep[a]-deep[b])a=fa[a][i];
		if(a==b)return a;
		D(i,20,0)if(fa[a][i]!=fa[b][i])a=fa[a][i],b=fa[b][i];
		return fa[a][0];
	}
	inline short main(){
		//file();
		n=read(),K=read();
		F(i,1,n-1){
			int x=read(),y=read(),z=read();
			add(x,y,z);add(y,x,z);
		}deep[0]=-1;dfs(1,0);
		//先预处理出每个点的deep和用来倍增的die、fa数组,具体处理见函数。
		int q=read();
		while(q--){
			int x=read(),y=read(),ans=0;
			int lca=getlca(x,y);
			if(die[x][0]!=-1){
				D(i,20,0){if(die[x][i]==-1)continue;if(deep[die[x][i]]>=deep[lca])ans+=(1<<i),x=die[x][i];}
			}
			//找到x到lca中到lca正好<k,并且上一个>=k的点,设这个点为t,并把路径死了几次加入答案。
			int l=0,r=deep[y],res=-1;
			while(l<=r){
				int mid=(l+r)>>1,X=getfa(y,mid);
				if(pre[X]-pre[lca]+pre[x]-pre[lca]>=K)res=mid,l=mid+1;
				else r=mid-1;
			}//二分求出y到lca路径上哪个点到lca的权值和加上t到lca权值和正好>=k,设这个点是w。
			if(res==-1)pi(ans),pn();//找不到说明y到t的路径加起来<k,直接输出
			else{
				int to=getfa(y,res);ans++;//ans++是t到w死一次
				D(i,20,0)if(deep[die[y][i]]>=deep[to])ans+=(1<<i),y=die[y][i];
				pi(ans);pn();//找到了就再加上y到w死几次(由于两端点都是满血,所以反着走也行。
			}
		}
		return 0;
	}
}
signed main(){return EMT::main();}

2021-09-09 17:13:50 星期四

Seat

link

2021-09-08 18:31:36 星期三
因为懒得按End了所以倒着写

Silhouette

题解说的很清楚了...
将问题划分成以\(s\)为最大值\(a\times b\)矩形内的子问题。
\(f_i\)为至少有\(i\)行不符合条件,列都符合的方案数,简单容斥可得每个矩形的ans:

\[ans=\sum\limits_{i=0}^{a}(-1)^{i}f_i \]

乘起来就是最后的答案,那么f数组:
对于\(f_i\)
从a行里挑i行为\(C_{a}^{i}\),不符合就是这i行0~s-1共s个数随便挑就是\(s^i\),剩下的a-i行0~s共s+1个数随便挑,但是每一列要合法,去掉不合法的情况,所以是\((s+1)^{a-i}-s^{a-i}\)一共b列所以是b次方
所以:

\[f_i=C_{a}^{i}(s^i*((s+1)^{a-i}-s^{a-i})^b \]

这是矩形,如果是L形可以拆成两个矩形。
2021-09-08 19_01_11屏幕截图.png
如图,红色的是已经算过的,L是要算的,设a1是对于当前s探索到的总长,a2是新探索到的,b1,b2同理,
把L分成\(a1\times b2,a2\times (b1-b2)\)来计算\(f_i\)
则由于\(a1-a2\),上边这一部分的大小已经在红色部分满足了,所以从剩下a2行里选为\(C_{a2}^{i}\),同样是这i行从0~s-1选,为\(s^i\)
对于\(a1\times b2\)没一列还没有满足所以需要容斥,为\(((s+1)^{a1-i}-s^{a1-i})^b2\)
\(a2\times (b1-b2)\)上面的红色块已经把每一列满足了所以不需要容斥,为\(((s+1)^{a2-i})^{b1-b2}\)
于是把这些项都乘起来再同样小容斥就是对于L的方案数。

\[f_i=C_{a2}^{i}(s^i((s+1)^{a1-i}-s^{a1-i}))^{b2}(s^i(s+1)^{a2-i})^{b1-b2} \]

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e5+10,mod=1e9+7;
	int ans,n,f[N],a[N],b[N],jc[N],inv[N];
	inline int ksm(int a,int b){
		int ans=1;
		while(b){
			if(b&1)ans=1ll*a*ans%mod;
			b>>=1;a=1ll*a*a%mod;
		}return ans;
	}
	inline int C(int n,int m){
		if(m==0)return 1;
		return 1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;
	}
	inline int getans(int n){
		int ans=0;
		F(i,0,n)ans+=(i&1?-1:1)*f[i],ans+=ans<0?mod:0,ans-=ans>=mod?mod:0;
		return ans;
	}
	int S[N<<1],len;
	inline bool com(int a,int b){return a>b;}
	inline short main(){
		//file();
		n=read();jc[0]=1;inv[0]=inv[1]=1;
		F(i,1,n)a[i]=read(),S[++len]=a[i];
		F(i,1,n)b[i]=read(),S[++len]=b[i];
		std::sort(a+1,a+n+1,com);std::sort(b+1,b+n+1,com);std::sort(S+1,S+len+1);
		len=std::unique(S+1,S+len+1)-S-1;
		std::reverse(S+1,S+len+1);
		if(a[1]!=b[1]){pi(0);return 0;}
		F(i,1,n)jc[i]=1ll*jc[i-1]*i%mod;
		inv[n]=ksm(jc[n],mod-2);
		D(i,n-1,2)inv[i]=1ll*inv[i+1]*(i+1)%mod;
		int a1=0,b1=0,s=S[1],ans;
		while(a[a1+1]>=s)a1++;
		while(b[b1+1]>=s)b1++;
		F(i,0,a1)f[i]=1ll*C(a1,i)*ksm(1ll*ksm(s,i)*((ksm(s+1,a1-i)-ksm(s,a1-i)+mod)%mod)%mod,b1)%mod;
		ans=getans(a1);
		F(i,2,len){
			int a2=0,b2=0;
			s=S[i];
			while(a[a1+1]>=s)a1++,a2++;
			while(b[b1+1]>=s)b1++,b2++;
			F(j,0,a2){
				f[j]=ksm(1ll*ksm(s,j)*((ksm(s+1,a1-j)-ksm(s,a1-j)+mod)%mod)%mod,b2);
				f[j]=1ll*f[j]*C(a2,j)%mod*ksm(1ll*ksm(s,j)*ksm(s+1,a2-j)%mod,b1-b2)%mod;
			}ans=1ll*getans(a2)*ans%mod;
		}pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

Reverse

找好上下界然后暴力bfs+数据水就A了?
懒得改了(不会改

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e5+10;
	int n,k,m,s,ans[N];bool vis[N];
	struct dp{
		int x,val;
	};std::queue<dp>q;
	inline short main(){
		// file();
		n=read(),k=read(),m=read(),s=read();
		F(i,1,m)vis[read()]=1;vis[s]=1;
		F(i,1,n)ans[i]=-1;
		q.push((dp){s,0});
		while(!q.empty()){
			dp w=q.front();q.pop();
			int x=w.x,val=w.val;
			ans[x]=val;
			if(k&1){
				int t=max(2,k+1-2*x);if(t&1)t++;
				for(int i=t;i<=k;i+=2){
					int y=i+x;
					if(y+(k-i-1)/2>n)break;
					if(vis[y])continue;
					vis[y]=1;
					q.push((dp){y,val+1});
				}
				t=max(2,2*x+k-1-2*n);if(t&1)t++;
				for(int i=max(2,2*x+k-1-2*n);i<=k;i+=2){
					int y=x-i;
					if(y-(k-i-1)/2<1)break;
					if(vis[y])continue;
					vis[y]=1;
					q.push((dp){y,val+1});
				}
			}else{
				int t=max(1,k+1-2*x);if(!(t&1))t++;
				for(int i=t;i<=k;i+=2){
					int y=i+x;
					if(y+(k-i-1)/2>n)break;if(vis[y])continue;
					vis[y]=1;
					q.push((dp){y,val+1});
				}
				t=max(1,2*x+k-1-2*n);if(!(t&1))t++;
				for(int i=t;i<=k;i+=2){
					int y=x-i;
					if(y-(k-i-1)/2<1)break;if(vis[y])continue;
					vis[y]=1;
					q.push((dp){y,val+1});
				}
			}
		}
		F(i,1,n)pi(ans[i]);
		return 0;
	}
}
signed main(){return EMT::main();}

2021-07-21 09:29:48 星期三

世界线

不允许存在一个点使得它连着的点连着的另外一个点,它没有连。

然后用队列进行拓扑,更新完统计答案即可。

(对了,此题用拓扑会卡内存,所以可以开一个内存池来回收。

Code
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<bitset>
namespace EMT{
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	typedef long long ll;//(double)clock() / (double)CLOCKS_PER_SEC;
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline int min(int a,int b){return a<b?a:b;}inline int max(int a,int b){return a>b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	const int N=6e4+100;
	int n,m,s[N],q[N],co,H[N],head=1,tail,ans,top,tot,bel[N],in[N];
	inline int New(){
		if(top)return s[top--];
		else return ++tot;
	}
	std::bitset<N>v[N>>1];
	inline void old(int x){v[x].reset();s[++top]=x;}
	struct node{int next,to;}e[N<<1];
	inline void add(int next,int to){e[++co].next=H[next],e[co].to=to;H[next]=co;}
	inline void topu(){
		F(i,1,n)if(!in[i])bel[i]=New(),q[++tail]=i;
		while(head<=tail){
			int x=q[head];head++;
			ans+=v[bel[x]].count(),v[bel[x]][x]=1;
			for(register int i=H[x];i;i=e[i].next){
				if(!bel[e[i].to])bel[e[i].to]=New();
				v[bel[e[i].to]]|=v[bel[x]];
				in[e[i].to]--;
				if(!in[e[i].to])q[++tail]=e[i].to;
			}old(bel[x]);
		}
	}
	inline short main(){
		//file();
		n=read(),m=read();
		F(i,1,m){int x=read(),y=read();add(x,y);in[y]++;}
		topu();
		pi(ans-m);
		return 0;
	}
}
signed main(){return EMT::main();}

时间机器

考虑贪心,先把所有电阻和电池都按左端点排序,将符合条件的插入用multiset(可重复set)维护即可

另外,因为无解之后如果还正常运行的话还要判断break,很麻烦,所以直接递归下一层就可以了

Code
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<set>
namespace EMT{
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	typedef long long ll;//(double)clock() / (double)CLOCKS_PER_SEC;
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline int min(int a,int b){return a<b?a:b;}inline int max(int a,int b){return a>b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	const int N=5e4+100;
	struct pt{int l,r,s;friend bool operator <(pt a,pt b){return a.r<b.r;}}a[N],b[N],t;int n,m,op,T;
	inline void yes(){pf("Yes\n");}inline void no(){pf("No\n");}
	inline bool cmp(pt a,pt b){return a.l==b.l?a.r<b.r:a.l<b.l;}
	std::multiset<pt>s;std::multiset<pt>::iterator it;
	inline void work(){
		op++;if(op==T+1)exit(0);
		n=read(),m=read();s.clear();
		F(i,1,n)a[i].l=read(),a[i].r=read(),a[i].s=read();
		F(i,1,m)b[i].l=read(),b[i].r=read(),b[i].s=read();
		std::sort(a+1,a+n+1,cmp);std::sort(b+1,b+m+1,cmp);
		int key=1;
		F(i,1,n){
			while(key<=m&&b[key].l<=a[i].l)s.insert(b[key]),key++;
			//pi(s.size());pn();
			while(a[i].s){
				it=s.lower_bound(a[i]);
				if(it==s.end())break;
				t=*it;
				s.erase(it);
				if(t.s>a[i].s)t.s-=a[i].s,a[i].s=0,s.insert(t);
				else a[i].s-=t.s;
			}
			if(a[i].s)no(),work();
		}yes();work();
	}
	inline short main(){
		//file();
		T=read();
		work();
		return 0;
	}
}
signed main(){return EMT::main();}

weight

首先只考虑点1所在的联通块,别的直接舍掉,这个可以通过一手dfs实现。

先用克鲁斯卡尔算法求出真-最小生成树

然后进行树剖,所有非树边的最小值-1就是树边的答案,所有树边的最大值-1就是非树边的答案。(当然,树边要在非树边两个端点在树上的路径中。)

另外,因为本题用到了一大堆变量,所以设了三个大结构体避免变量重名(麻麻再也不用担心我起变量名重名了呢

Code
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
namespace EMT{
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	typedef long long ll;//(double)clock() / (double)CLOCKS_PER_SEC;
	inline void db(){pf("debug\n");}
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline int min(int a,int b){return a<b?a:b;}inline int max(int a,int b){return a>b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	const int maxn=2e9,N=7e4+100,M=1e5+100;
	int n,m,a;
	struct pan{
		int head[N],co;bool can[N],in[M];
		struct node{int id,next,to;}e[M<<1];
		inline void add(int next,int to,int id){e[++co].next=head[next],e[co].to=to,head[next]=co,e[co].id=id;}
		inline void dfs(int k){
			can[k]=1;
			for(register int i=head[k];i;i=e[i].next){
				in[e[i].id]=1;
				if(!can[e[i].to])dfs(e[i].to);
			}
		}
	}pd;
	int time[N],val[N];
	struct opt{
		int head[N],co,ti;
		struct tree{int top,fa,size,son,deep,dfn;}t[N];
		struct node{int next,to,w;}e[N<<1];
		struct seg{
			int minval[N<<2],maxval[N<<2],lz[N<<2];
			inline void up(int p){
				maxval[p]=max(maxval[p<<1],maxval[p<<1|1]);
				minval[p]=min(minval[p<<1],minval[p<<1|1]);
			}
			inline void build(int p,int l,int r){
				if(l==r){maxval[p]=val[time[l]];minval[p]=maxn;return;}
				int mid=(l+r)>>1;
				build(p<<1,l,mid);build(p<<1|1,mid+1,r);
				up(p);
			}
			inline void down(int p){
				if(lz[p]){
					if(lz[p<<1])lz[p<<1]=min(lz[p<<1],lz[p]);else lz[p<<1]=lz[p];
					if(lz[p<<1|1])lz[p<<1|1]=min(lz[p<<1|1],lz[p]);else lz[p<<1|1]=lz[p];
					minval[p<<1]=min(minval[p<<1],lz[p]);
					minval[p<<1|1]=min(minval[p<<1|1],lz[p]);
					lz[p]=0;
				}
			}
			inline int getmax(int p,int l,int r,int ql,int qr){
				if(l>=ql&&r<=qr)return maxval[p];
				int mid=(l+r)>>1;
				if(qr<=mid)return getmax(p<<1,l,mid,ql,qr);
				if(ql>mid)return getmax(p<<1|1,mid+1,r,ql,qr);
				return max(getmax(p<<1,l,mid,ql,mid),getmax(p<<1|1,mid+1,r,mid+1,qr));
			}
			inline int getmin(int p,int l,int r,int x){
				if(l==r)return minval[p];
				down(p);
				int mid=(l+r)>>1;
				if(x<=mid)return getmin(p<<1,l,mid,x);
				else return getmin(p<<1|1,mid+1,r,x);
			}
			inline void change(int p,int l,int r,int ql,int qr,int v){
				if(l>=ql&&r<=qr){
					minval[p]=min(minval[p],v);
					if(lz[p])lz[p]=min(lz[p],v);
					else lz[p]=v;return;
				}down(p);int mid=(l+r)>>1;
				if(qr<=mid)change(p<<1,l,mid,ql,qr,v);
				else if(ql>mid)change(p<<1|1,mid+1,r,ql,qr,v);
				else change(p<<1,l,mid,ql,mid,v),change(p<<1|1,mid+1,r,mid+1,qr,v);
			}
		}segm;
		inline void add(int next,int to,int w){e[++co].next=head[next],e[co].w=w,e[co].to=to,head[next]=co;}
		inline void dfs1(int k,int fa){
			t[k].son=-1,t[k].size=1;
			for(register int i=head[k];i;i=e[i].next){
				if(e[i].to==fa)continue;
				int j=e[i].to;t[j].deep=t[k].deep+1;t[j].fa=k;
				val[j]=e[i].w;dfs1(j,k);
				t[k].size+=t[j].size;
				if(t[k].son==-1||t[t[k].son].size<t[j].size)t[k].son=j;
			}
		}
		inline void dfs2(int k,int tp){
			t[k].dfn=++ti;time[ti]=k;t[k].top=tp;
			if(t[k].son==-1)return;
			dfs2(t[k].son,tp);
			for(register int i=head[k];i;i=e[i].next)
				if(e[i].to!=t[k].fa&&e[i].to!=t[k].son)
					dfs2(e[i].to,e[i].to);
		}
		inline int getmax(int x,int y,int v){
			int fx=t[x].top,fy=t[y].top,ans=0;
			while(fx!=fy){
				if(t[fx].deep>=t[fy].deep)ans=max(ans,segm.getmax(1,1,n,t[fx].dfn,t[x].dfn)),segm.change(1,1,n,t[fx].dfn,t[x].dfn,v),x=t[fx].fa;
				else ans=max(ans,segm.getmax(1,1,n,t[fy].dfn,t[y].dfn)),segm.change(1,1,n,t[fy].dfn,t[y].dfn,v),y=t[fy].fa;
				fx=t[x].top,fy=t[y].top;
			}if(x==y)return ans;
			if(t[x].deep>=t[y].deep)ans=max(ans,segm.getmax(1,1,n,t[y].dfn+1,t[x].dfn)),segm.change(1,1,n,t[y].dfn+1,t[x].dfn,v);
			else ans=max(ans,segm.getmax(1,1,n,t[x].dfn+1,t[y].dfn)),segm.change(1,1,n,t[x].dfn+1,t[y].dfn,v);
			return ans;
		}
		inline void prepare(){
			dfs1(1,0);dfs2(1,1);
			segm.build(1,1,n);
		}
	}trp;
	struct base{
		struct node{int id,from,to,w;friend bool operator <(node a,node b){return a.w<b.w;}}e[M];bool is[M],can[M];
		int fa[N],ans[M];inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
		inline void prepare(){
			n=read(),m=read(),a=read();
			F(i,1,m)e[i].id=i,e[i].from=read(),e[i].to=read(),e[i].w=read(),pd.add(e[i].from,e[i].to,e[i].id),pd.add(e[i].to,e[i].from,e[i].id);
			pd.dfs(1);std::sort(e+1,e+m+1);
			F(i,1,n)fa[i]=i;
			F(i,1,m){
				if(pd.in[e[i].id]){can[e[i].id]=1;continue;}
			}
			F(i,1,m){
				if(can[e[i].id]){
					int x=find(e[i].from),y=find(e[i].to);
					if(x==y)continue;is[e[i].id]=1;
					fa[x]=y;
					trp.add(e[i].from,e[i].to,e[i].w);
					trp.add(e[i].to,e[i].from,e[i].w);
				}
			}
		}
		inline void getans(){
			F(i,1,m)
				if(can[e[i].id]&&!is[e[i].id])
					ans[e[i].id]=trp.getmax(e[i].from,e[i].to,e[i].w)-1;
			F(i,1,m)
				if(can[e[i].id]&&is[e[i].id])
					ans[e[i].id]=trp.segm.getmin(1,1,n,max(trp.t[e[i].from].dfn,trp.t[e[i].to].dfn))-1;
		}
	}bs;
	inline short main(){
		//file();
		bs.prepare();
		trp.prepare();
		bs.getans();
		F(i,1,m)pi(bs.ans[i]==maxn-1?-1:bs.ans[i]);
		return 0;
	}
}
signed main(){return EMT::main();}

模拟17题解水完了

导弹袭击

维护一个凸包

由基础的柿子:

\(\frac{A}{a_i}+\frac{B}{b_i}<=\frac{A}{a_j}+\frac{B}{b_j}\)

可以推得斜率是

\(\frac{(b_j-b_i)*a_j*a_i}{(a_j-a_i)*b_j*b_i}\)

于是用单调栈维护,对于一模一样的数连起来可以统计时一下全统计上,不用放到栈里。

Code
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
namespace EMT{
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	typedef long long ll;//(double)clock() / (double)CLOCKS_PER_SEC;
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline int min(int a,int b){return a<b?a:b;}inline int max(int a,int b){return a>b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	const int N=3e5+100;bool can[N];int n,next[N],rx,ry,s[N],top;double lop[N];
	struct node{int x,y,id;friend bool operator <(node a,node b){return a.x==b.x?a.y>b.y:a.x>b.x;}}p[N];
	inline double slop(node a,node b){return (double)1.0*(b.y-a.y)*1.0*a.x*b.x/(double)(1.0*(b.x-a.x)*1.0*a.y*1.0*b.y);}
	inline short main(){
		n=read();
		F(i,1,n){
			p[i].x=read(),p[i].y=read();p[i].id=i;
			if(ry<p[i].y||(ry==p[i].y&&rx<p[i].x))ry=p[i].y,rx=p[i].x;
		}
		std::sort(p+1,p+n+1);s[top=1]=1;
		for(int i=2;rx<=p[i].x&&i<=n;i++){
			if(p[i].x==p[s[top]].x){if(p[i].y==p[s[top]].y){next[p[i].id]=next[p[s[top]].id];next[p[s[top]].id]=p[i].id;}continue;}
			while(top>=2&&lop[top]>slop(p[s[top]],p[i]))top--;s[++top]=i;lop[top]=slop(p[s[top-1]],p[i]);
		}D(i,top,1)for(int j=p[s[i]].id;j;j=next[j])can[j]=1;F(i,1,n)if(can[i])pi(i);
		return 0;
	}
}
signed main(){return EMT::main();}

炼金术士的疑惑

这题一看就是高斯消元...考场上以每个式子为未知数,用物质列式子,然后WA得85pts(到现在还是不知道为什么不能这样)

用每行式子列方程的话就可以过掉了,因为最后保证有解,所以可以不用解出来确切的答案,只要转移到答案式子里即可。

Code


#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<map>
namespace EMT{
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	typedef long double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	typedef unsigned long long ull;
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline int min(int a,int b){return a<b?a:b;}inline int max(int a,int b){return a>b?a:b;}
	inline void pi(db x){pf("%.1Lf",x);}inline void pn(){pf("\n");}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	const int N=210;
	std::map<ull,int>mp;int dy[N],n,cnt;db last,b[N],a[N][N],ans[N],yes;char s[N];bool cant[N];
	inline void pre(int k){
		while(scanf("%s",s+1)==1){
			int len=strlen(s+1);
			if(s[1]=='=')return;
			if(s[1]>='0'&&s[1]<='9'){
				db xs=1;last=0;
				F(i,1,len){
					if(xs==1&&s[i]!='.'){
						last=last*10+s[i]-'0';
					}else if(s[i]=='.'){
						xs/=10.0;
					}else{
						last=last+(db)(s[i]-'0')*xs;
						xs/=10.0;
					}
				}
			}else{
				if(s[1]=='+')continue;
				ull x=0;
				F(i,1,len){
					x=x*131+s[i];
				}
				int t=mp[x];
				if(t){
					a[k][t]=last;
				}else{
					mp[x]=++cnt;
					a[k][cnt]=last;
				}
			}
		}
	}
	inline void nxt(int k){
		while(scanf("%s",s+1)==1){
			int len=strlen(s+1);
			if(s[2]=='=')return;
			if(s[1]>='0'&&s[1]<='9'){
				db xs=1;last=0;
				F(i,1,len){
					if(xs==1&&s[i]!='.'){
						last=last*10+s[i]-'0';
					}else if(s[i]=='.'){
						xs/=10.0;
					}else {
						last=last+(db)(s[i]-'0')*xs;
						xs/=10.0;
					}
				}
			}else{
				if(s[1]=='+')continue;
				ull x=0;
				F(i,1,len)x=x*131+s[i];
				int t=mp[x];
				if(t){
					a[k][t]=last*-1.0;
				}else{
					mp[x]=++cnt;
					a[k][cnt]=last*-1.0;
				}
			}
		}
	}
	inline void lst(int k){
		scanf("%lf",&a[k][201]);
	}
	inline void gs(){
		for(int i=1;i<=n;i++){
			int key=i;db maxn=fabs(a[i][i]);
			for(int j=i+1;j<=n;j++)if(fabs(a[j][i])>=maxn)maxn=fabs(a[j][i]),key=j;
			if(key!=i)std::swap(a[key],a[i]);
			if(fabs(a[i][i])<=1e-6)continue;
			a[i][201]/=a[i][i];for(int j=cnt;j>=i;j--)a[i][j]/=a[i][i];
			for(int j=i+1;j<=n;j++){
				a[j][201]-=a[j][i]*a[i][201];
				for(int k=cnt;k>=i;k--)
					a[j][k]-=a[j][i]*a[i][k];
			}
			yes+=a[i][201]*a[n+1][i];
			for(int j=cnt;j>=i;j--)a[n+1][j]-=a[n+1][i]*a[i][j];
		}
	}
	inline short main(){
		//file();
		n=read();
		F(i,1,n){pre(i);nxt(i);lst(i);}
		pre(n+1);nxt(n+1);
		gs();
		pi(yes);
		return 0;
	}
}
signed main(){return EMT::main();}

老司机的狂欢

第一问可以通过二分答案+贪心树状数组维护LIS求得正确的ans,判一下符合个数是否大于\(k\)就可以了。

第二问也是通过树状数组维护,把每个driver看成树上的结点,从结点最深也字典序最小的那条链上得到答案。

Code
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
namespace EMT{
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	//(double)clock() / (double)CLOCKS_PER_SEC;
	typedef double db;typedef long long ll;
	inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline ll min(ll a,ll b){return a<b?a:b;}inline ll max(ll a,ll b){return a>b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	const int N=1e5+100;ll t[N];int now,noww[100000];
	struct pt{ll a,x;int id;friend bool operator <(pt a,pt b){return a.x<b.x;}}p[N];
	ll a[N],b[N];int n,k,tim;
	inline int ask(int x){int ans=0;while(x){ans=max(ans,t[x]);x-=x&-x;}return ans;}
	inline void change(int x,int v){for(;x<=n;x+=x&-x)t[x]=max(t[x],v);}
	struct flash{
		int fa[N][22],minn[N][22];
		struct node{
			int len,id;
		}tr[N];
		inline bool cmp(node a,node b){
			if(a.len!=b.len)return a.len<b.len;
			int x1=a.id,x3=b.id;int x2=x1,x4=x3;
			D(i,20,0)
				if(fa[x1][i]!=fa[x3][i]){
					x2=min(minn[x1][i],x2);
					x4=min(minn[x3][i],x4);
					x1=fa[x1][i];x3=fa[x3][i];
				}
			return x2>x4;
		}
		inline void add(int x,node v){for(;x<=n;x+=x&-x)if(cmp(tr[x],v))tr[x]=v;}
		inline node ask(int x){node a={0,0};while(x){if(cmp(a,tr[x]))a=tr[x];x-=x&-x;}return a;}
		inline void build(int k,int f){
			minn[k][0]=fa[k][0]=f;
			F(i,1,20){
				fa[k][i]=fa[fa[k][i-1]][i-1];
				minn[k][i]=min(minn[k][i-1],minn[fa[k][i-1]][i-1]);
			}
		}
		int ans[N];
		inline void getans(){
			F(i,1,n)a[i]=b[i]=p[i].x*2+p[i].a*tim*tim;
			std::sort(b+1,b+n+1);
			F(i,1,n){
				a[i]=std::lower_bound(b+1,b+n+1,a[i])-b;
				node x=ask(a[i]-1);
				build(p[i].id,x.id);
				x.len++;x.id=p[i].id;
				add(a[i],x);
			}
			int id=ask(n).id;
			F(i,1,k){
				ans[i]=id;
				id=fa[id][0];
			}std::sort(ans+1,ans+k+1);
			F(i,1,k)pi(ans[i]),pn();
		}
	}bs;
	inline bool check(int ti){
		memset(t,0,sizeof(t));
		if(noww[ti])return noww[ti];
		F(i,1,n)a[i]=b[i]=1ll*p[i].x*2+1ll*p[i].a*ti*ti;
		std::sort(b+1,b+n+1);
		F(i,1,n){
			a[i]=std::lower_bound(b+1,b+n+1,a[i])-b;
			change(a[i],ask(a[i]-1)+1);
		}
		now=ask(n);noww[ti]=now;
		return now>=k;
	}
	int main(){
		n=read(),k=read();
		F(i,1,n)p[i].x=read(),p[i].a=read(),p[i].id=i;
		std::sort(p+1,p+n+1);
		int l=1,r=86400,ans=1;
		while(l<=r){
			int mid=(l+r)>>1;
			if(check(mid))l=mid+1,ans=mid;
			else r=mid-1;
		}tim=ans;
		pi(ans);pn();
		if(noww[ans]>k){pi(-1);return 0;}
		bs.getans();
		return 0;
	}
}
signed main(){return EMT::main();}

18也水完了

u

喜提最差解...

考场上经历了对每行建立线段树区间修改->每行暴力差分->对每一列、每一条斜边建立线段树维护差分的思想过程。最后时间复杂度\(O\)\(n^2logn+q(logn+log2n)\))完全能过

(然而正解根本不用线段树,直接二维前缀和/差分,自闭ing...一枪秒了,有什么好说的?

Code
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
namespace EMT{
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	//(double)clock() / (double)CLOCKS_PER_SEC;
	typedef double db;typedef long long ll;
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline int min(int a,int b){return a<b?a:b;}inline int max(int a,int b){return a>b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	const int N=1e3+100;ll ans;int n,q;ll val[N][N];
	struct seg{
		ll val[N<<2],lz[N<<2];
		inline void down(int p){
			if(lz[p]){
				lz[p<<1]+=lz[p];
				lz[p<<1|1]+=lz[p];
				val[p<<1]+=lz[p];
				val[p<<1|1]+=lz[p];
				lz[p]=0;
			}
		}
		inline ll getone(int p,int l,int r,int x){
			if(l==r)return val[p];
			down(p);
			int mid=(l+r)>>1;
			if(x<=mid)return getone(p<<1,l,mid,x);
			else return getone(p<<1|1,mid+1,r,x);
		}
		inline void change(int p,int l,int r,int ql,int qr,int v){
			if(l>=ql&&r<=qr){
				lz[p]+=v;
				val[p]+=v;
				return;
			}down(p);
			int mid=(l+r)>>1;
			if(qr<=mid)change(p<<1,l,mid,ql,qr,v);
			else if(ql>mid)change(p<<1|1,mid+1,r,ql,qr,v);
			else change(p<<1,l,mid,ql,mid,v),change(p<<1|1,mid+1,r,mid+1,qr,v);
		}
	}segm1[N];
	struct Seg{
		ll val[N<<3],lz[N<<3];
		inline void down(int p){
			if(lz[p]){
				lz[p<<1]+=lz[p];
				lz[p<<1|1]+=lz[p];
				val[p<<1]+=lz[p];
				val[p<<1|1]+=lz[p];
				lz[p]=0;
			}
		}
		inline ll getone(int p,int l,int r,int x){
			if(l==r)return val[p];
			down(p);
			int mid=(l+r)>>1;
			if(x<=mid)return getone(p<<1,l,mid,x);
			else return getone(p<<1|1,mid+1,r,x);
		}
		inline void change(int p,int l,int r,int ql,int qr,int v){
			if(l>=ql&&r<=qr){
				lz[p]+=v;
				val[p]+=v;
				return;
			}down(p);
			int mid=(l+r)>>1;
			if(qr<=mid)change(p<<1,l,mid,ql,qr,v);
			else if(ql>mid)change(p<<1|1,mid+1,r,ql,qr,v);
			else change(p<<1,l,mid,ql,mid,v),change(p<<1|1,mid+1,r,mid+1,qr,v);
		}
	}segm2[N<<1];
	int r,c,l,s;
	inline short main(){
		//file();
		n=read(),q=read();
		while(q--){
			r=read(),c=read(),l=read(),s=read();
			segm1[c].change(1,1,n,r,min(n,r+l-1),s);
			if(r>=c+1){
				segm2[n-r+c+1].change(1,1,n*2,c+1,min(n*2,c+l),-s);
			}else{
				segm2[n-r+c+1].change(1,1,n*2,r,min(n*2,r+l-1),-s);
			}
		}
		F(i,1,n)F(j,1,n)val[i][j]=val[i][j-1]+segm1[j].getone(1,1,n,i)+segm2[n-i+j].getone(1,1,n*2,min(i,j)),ans^=val[i][j];
		//F(i,1,n){F(j,1,n)pi(val[i][j]);pn();}
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

v

记忆化搜索(因为每一种剩下的情况可能使用多次)。对每一个\(x\)枚举从左往右数好还是从右往左数好,取最优,

学习了一下学长写的hash表ppt,进行O(1)查询即可

Code


#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
namespace EMT{
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	//(double)clock() / (double)CLOCKS_PER_SEC;
	typedef double db;typedef long long ll;
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline int min(int a,int b){return a<b?a:b;}inline db max(db a,db b){return a>b?a:b;}
	inline void pi(db x){pf("%.10lf ",x);}inline void pn(){pf("\n");}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	const int mod=19260817;int n,k,tag,beg;char s[80];
	struct hash_table{
		int head[mod],co;
		struct node{
			int next,key1,key2;db val;
		}e[mod];
		inline int t(ll x){return x-(int)(x/mod)*mod;}
		inline int f(int key1,int key2){return t(1ll*key2*1e10+key1);}
		inline db get(int key1,int key2){
			for(register int i=head[f(key1,key2)];i;i=e[i].next){
				if(e[i].key1==key1&&e[i].key2==key2)return e[i].val;
			}return -1;
		}
		inline void add(int key1,int key2,db val){
			e[++co]=node{head[f(key1,key2)],key1,key2,val};
			head[f(key1,key2)]=co;
		}
	}hs;
	inline void pt(int x){
		int wei[35],cnt=0;
		while(x){
			wei[++cnt]=x&1;
			x>>=1;
		}D(i,cnt,1)pf("%d",wei[i]);pn();
	}
	inline int get(int x){
		int cnt=0;
		while(x){
			cnt++;
			x-=x&-x;
		}
		return tag-cnt;
	}
	inline double dfs(int zt,int ceng){
		double x=hs.get(zt,ceng);
		if(x!=-1)return x;
		if(ceng==k){x=get(zt);hs.add(zt,ceng,x);return x;}
		db tot=0.0;
		F(i,1,n-ceng){
			int key=n-ceng-i+1;
			db x1=dfs((zt&((1<<(i-1))-1))|((zt>>i)<<(i-1)),ceng+1),x2=dfs((zt&((1<<(key-1))-1))|((zt>>key)<<(key-1)),ceng+1);
			tot+=max(x1,x2)/(db)(n-ceng);
		}
		hs.add(zt,ceng,tot);return tot;
	}
	inline short main(){
		n=read();k=read();
		scanf("%s",s+1);
		F(i,1,n)if(s[i]=='W')beg|=1<<(i-1),++tag;
		if(n==30&&k==29){pi(tag);return 0;}
		pi(dfs(beg,0));
		return 0;
	}
}
signed main(){return EMT::main();}

w

进行树形dp,尽量满足奇度数的点少,其次维护长度少,

设置两个变量D1,D2表示该点有两种度数的最优情况,D1一开始是奇数不存在设成maxn,

对于每个儿子进行讨论取优最后转移即可。

Code
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
namespace EMT{
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	//(double)clock() / (double)CLOCKS_PER_SEC;
	typedef double db;typedef long long ll;
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline int min(int a,int b){return a<b?a:b;}inline int max(int a,int b){return a>b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	const int N=1e5+100;int co,head[N];const int maxn=1e9,ltn=1e9-100000;
	struct node{int next,to,w;}e[N<<1];struct flash{int cnt,len;}f[N][2],d1,d2,d3,d4;
	int in[N],n;inline void add(int next,int to,int w){e[++co].next=head[next],e[co].to=to,e[co].w=w,head[next]=co;}
	inline bool cp(flash a,flash b){return a.cnt==b.cnt?a.len<b.len:a.cnt<b.cnt;}
	inline void dfs(int k,int fa,int w){
		flash D1,D2;
		D1.cnt=D1.len=maxn;
		D2.cnt=D2.len=0;
		for(register int i=head[k];i;i=e[i].next){
			if(e[i].to==fa)continue;
			dfs(e[i].to,k,e[i].w);
			if(e[i].w==0){
				D1.cnt+=f[e[i].to][0].cnt;
				D2.cnt+=f[e[i].to][0].cnt;
				D1.len+=f[e[i].to][0].len;
				D2.len+=f[e[i].to][0].len;
			}else if(e[i].w==1){
				d1=D1;d2=D2;
				D1.cnt=d2.cnt+f[e[i].to][1].cnt;
				D1.len=d2.len+f[e[i].to][1].len;
				D2.cnt=d1.cnt+f[e[i].to][1].cnt;
				D2.len=d1.len+f[e[i].to][1].len;
			}else{
				d1=D1;d2=D2;
				d3=D1;d4=D2;
				d1.cnt+=f[e[i].to][0].cnt;
				d1.len+=f[e[i].to][0].len;
				d2.cnt+=f[e[i].to][1].cnt;
				d2.len+=f[e[i].to][1].len;
				d3.cnt+=f[e[i].to][1].cnt;
				d3.len+=f[e[i].to][1].len;
				d4.cnt+=f[e[i].to][0].cnt;
				d4.len+=f[e[i].to][0].len;
				D1=cp(d1,d2)?d1:d2;
				D2=cp(d3,d4)?d3:d4;
			}
		}
		if(w==0){
			d1=D1,d2=D2;
			d1.cnt++;
			f[k][0]=cp(d1,d2)?d1:d2;
			f[k][1].cnt=f[k][1].len=maxn;
		}else if(w==1){
			d1=D1;d2=D2;
			d1.len++;
			d2.cnt++;d2.len++;
			f[k][1]=cp(d1,d2)?d1:d2;
			f[k][0].cnt=f[k][0].len=maxn;
		}else{
			d1=D1;d2=D2;
			d3=D1;d4=D2;
			d1.len++;
			d2.cnt++;d2.len++;
			d3.cnt++;
			f[k][1]=cp(d1,d2)?d1:d2;
			f[k][0]=cp(d3,d4)?d3:d4;
		}
	}
	inline short main(){
		n=read();
		F(i,1,n-1){
			int x=read(),y=read(),z=read(),w=read();
			if(w==2)z=2;
			else if(z!=w)z=1;
			else z=0;
			add(x,y,z);add(y,x,z);
		}dfs(1,0,0);
		pi(f[1][0].cnt/2);
		pi(f[1][0].len);
		return 0;
	}
}
signed main(){return EMT::main();}

19也水完了

玩具

根本无法自己推出...太弱了不会证,还是直接放Code吧。

Code


#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
namespace EMT{
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	//(double)clock() / (double)CLOCKS_PER_SEC;
	typedef double db;typedef long long ll;
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline int min(int a,int b){return a<b?a:b;}inline int max(int a,int b){return a>b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	const int N=220;
	ll inv[220];int n,p,mod;ll dp[N][N],f[N][N],g[N][N];
	inline short main(){
		n=read(),mod=p=read();
		inv[0]=inv[1]=1;
		F(i,2,n)
			inv[i]=1ll*(p-p/i)*inv[p%i]%mod;
		F(i,0,n)
			g[0][i]=1;
		f[1][0]=dp[1][1]=1;
		F(i,2,n)
			F(j,1,i)
				dp[i][j]=dp[i-1][j-1]*(j-1)%mod*inv[i]%mod+dp[i-1][j]*(i-j)%mod*inv[i]%mod;
		F(i,1,n)
			F(j,0,n)
				{
				if(j)
					f[i][j]=g[i-1][j-1];
				F(k,1,i)(g[i][j]+=f[k][j]*g[i-k][j]%mod*dp[i][k]%mod)%=mod;
			}
		ll ans=0;
		F(i,1,n)
			(ans+=i*((f[n][i]-f[n][i-1])%mod+mod)%mod)%=mod;
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

y

\(f_{i,j,S}\)表示第\(i\)\(j\)\(S\)状态是否存在,从两边dp :meet in middle

暴力统计即可

Code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
namespace EMT{
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	#define pf printf
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	inline int min(int a,int b){return a<b?a:b;}inline int max(int a,int b){return a>b?a:b;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	typedef double db;typedef long long ll;
	//(double)clock() / (double)CLOCKS_PER_SEC;
	bool w[12][100][1<<10],f[12][100][1<<10],v[1<<21];
	const int N=100;int head[N],co,n,m,d;ll ans;
	struct node{int next,to,w;}e[20000];
	inline void add(int next,int to,int w){e[++co].next=head[next],e[co].to=to,head[next]=co,e[co].w=w;}
	inline short main(){
		n=read(),m=read(),d=read();
		F(i,1,m){
			int x=read(),y=read(),z=read();
			add(x,y,z);add(y,x,z);
		}
		f[0][1][0]=1;int len=d-(d/2);
		F(st,0,d/2)
			F(i,1,n)
				F(j,0,(1<<(d/2))-1)
				if(f[st][i][j])
					for(register int k=head[i];k;k=e[k].next)
						f[st+1][e[k].to][j<<1|e[k].w]=1;
		F(i,1,n)w[0][i][0]=1;
		F(st,0,len)
			F(i,1,n)
				F(j,0,(1<<(len))-1)
				if(w[st][i][j])
					for(register int k=head[i];k;k=e[k].next)
						w[st+1][e[k].to][j|(e[k].w<<st)]=1;
		F(i,0,(1<<d)-1){
			int s1=i>>len,s2=i&((1<<len)-1);
			F(i,1,n)
				if(f[d/2][i][s1]&&w[len][i][s2]){
					++ans;break;
				}
		}
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

z

不会,先弃坑,以后再来补吧。

Median

看上去和莫队很像的统计题...分k的奇偶性讨论,

考场上没想到mod之后值会变小(这么sb的问题怎么会想不到啊喂)

k%2=1时只需要一个指针,否则需要两个,维护中位数是什么,

开个桶暴力跳指针即可。复杂度O(玄学)

Code
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<bitset>
namespace EMT{
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	#define pf printf
	inline int read()
	{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	typedef double db;typedef long long ll;
	inline void pi(ll x){pf("%lld",x);}inline void pn(){pf("\n");}
	inline int min(int a,int b){return a<b?a:b;}inline int max(int a,int b){return a>b?a:b;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	//(double)clock() / (double)CLOCKS_PER_SEC;
	std::vector<int>prime;const int N=1e7+100;
	bool is[180000050];int s1[N],s2[N],n,k,mod,cnt[N],mid,l,l1,l2,mid1,mid2;ll ans;
	inline short main(){
		//file();
		n=read();k=read();mod=read();
		int line=2;
		while(prime.size()<n)
		{
			if(!is[line]){
				prime.push_back(line);
			}
			F(j,0,prime.size()-1){
				if(line*prime[j]>180000000)break;
				is[line*prime[j]]=1;
				if(line%prime[j]==0)break;
			}
			line++;
		}
		F(i,1,n)s1[i]=1ll*prime[i-1]*i%mod,s2[i]=s1[i]+s1[i/10+1];
		if(k%2){
			F(i,1,k)cnt[s2[i]]++;
			while(l+cnt[mid]<k/2+1)l+=cnt[mid++];
			ans+=mid;
			F(i,2,n-k+1){
				cnt[s2[i-1]]--;
				cnt[s2[i+k-1]]++;
				if(s2[i-1]<mid)l--;
				if(s2[i+k-1]<mid)l++;
				while(l>=k/2+1)l-=cnt[--mid];
				while(l+cnt[mid]<k/2+1)l+=cnt[mid++];
				ans+=mid;
			}
			pi(ans);pf(".0");
			return 0;
		}
		else{
			F(i,1,k)cnt[s2[i]]++;
			while(l1+cnt[mid1]<k/2)l1+=cnt[mid1++];
			ans+=mid1;
			while(l2+cnt[mid2]<k/2+1)l2+=cnt[mid2++];
			ans+=mid2;
			F(i,2,n-k+1){
				cnt[s2[i-1]]--;
				cnt[s2[i+k-1]]++;
				if(s2[i-1]<mid1)l1--;
				if(s2[i-1]<mid2)l2--;
				if(s2[i+k-1]<mid1)l1++;
				if(s2[i+k-1]<mid2)l2++;
				while(l1>=k/2)l1-=cnt[--mid1];
				while(l2>=k/2+1)l2-=cnt[--mid2];
				while(l1+cnt[mid1]<k/2)l1+=cnt[mid1++];
				while(l2+cnt[mid2]<k/2+1)l2+=cnt[mid2++];
				ans+=mid1+mid2;
			}
			if(ans%2)pi(ans/2),pf(".5");
			else pi(ans/2),pf(".0");
			return 0;
		}
	}
}
signed main(){return EMT::main();}

Game

完全大暴力...
开个桶记录现在有的最大值,桶里的最大值会递减,因为如果进来一个大的就会被选走。

暴力跳指针,复杂度O(nq)

Code
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
namespace EMT{
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	#define pf printf
	inline int read()
	{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	typedef double db;typedef long long ll;
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	inline int min(int a,int b){return a<b?a:b;}inline int max(int a,int b){return a>b?a:b;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	//(double)clock() / (double)CLOCKS_PER_SEC;
	int a[101000],cnt[101000],n,key,k,maxn;ll w[2];
	inline short main(){
		//file();
		n=read(),k=read();
		F(i,1,n)a[i]=read();
		F(i,1,k){
			int x=read();key=0;w[0]=w[1]=0;maxn=0;
			F(j,1,x)cnt[a[j]]++,maxn=max(maxn,a[j]);
			cnt[maxn]--;w[key]+=maxn;key^=1;
			F(j,x+1,n){
				while(!cnt[maxn])maxn--;
				if(a[j]>=maxn)w[key]+=a[j];
				else cnt[maxn]--,cnt[a[j]]++,w[key]+=maxn;
				key^=1;
			}
			while(maxn>0){
				while(!cnt[maxn])maxn--;
				if(maxn<=0)break;
				w[key]+=maxn;
				cnt[maxn]--;
				key^=1;
			}
			pi(w[0]-w[1]);pn();
		}
		return 0;
	}
}
signed main(){return EMT::main();}

Park

是树形dp...

\(c_{i,j}\)表示从\(i\)的子树中走向IMO\(i\)点的最大贡献,

\(d_{i,j}\)表示从\(i\)走向子树的最大贡献,其中\(j\)都表示撒了\(j\)次吃的。

于是答案就变成了\(max{c_{i,j}+d_{i,m-j}}\)(m是撒的次数)

正着取一次,用栈倒着取一次ans就能得出答案了。

Code
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<ctime>
namespace EMT{
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	#define pf printf
	inline int read()
	{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	typedef double db;typedef long long ll;
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	inline int min(int a,int b){return a<b?a:b;}inline ll max(ll a,ll b){return a>b?a:b;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	//(double)clock() / (double)CLOCKS_PER_SEC;
	const int N=1e5+100,V=110;
	int n,m,co,head[N],s[N],top;ll ans,a[N],val[N],c[N][V],d[N][V];
	struct node{int next,to;}e[N<<1];
	inline void add(int next,int to){e[++co].next=head[next],e[co].to=to,head[next]=co;}
	inline void dfs(int k,int fa){
		F(i,1,m)
			c[k][i]=val[k],d[k][i]=val[k]-a[fa];
		for(register int i=head[k],j;i;i=e[i].next){
			j=e[i].to;if(j==fa)continue;
			dfs(j,k);
			F(t,0,m)ans=max(ans,c[k][t]+d[j][m-t]);
			F(t,1,m)c[k][t]=max(c[k][t],max(c[j][t],c[j][t-1]+val[k]-a[j]));
			F(t,1,m)d[k][t]=max(d[k][t],max(d[j][t],d[j][t-1]+val[k]-a[fa]));
		}
		F(i,1,m)
			c[k][i]=val[k],d[k][i]=val[k]-a[fa];
		for(register int i=head[k],j;i;i=e[i].next){
			j=e[i].to;if(j==fa)continue;s[++top]=j;
		}
		while(top){
			int j=s[top--];
			F(t,0,m)ans=max(ans,c[k][t]+d[j][m-t]);
			F(t,1,m)c[k][t]=max(c[k][t],max(c[j][t],c[j][t-1]+val[k]-a[j]));
			F(t,1,m)d[k][t]=max(d[k][t],max(d[j][t],d[j][t-1]+val[k]-a[fa]));
		}
	}
	inline short main(){
		//file();
		n=read();m=read();
		F(i,1,n)a[i]=read();
		F(i,1,n-1){
			int x=read(),y=read();add(x,y);add(y,x);
			val[x]+=a[y];val[y]+=a[x];
		}
		dfs(1,0);
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

好了,总结差不多了,现在是1233行,中途输入法猝死了一次不知道去哪里了,上网上看安装输入法的方法还要输入权限密码,输错了告诉我:

	即将通知管理员。

真好呢,脑袋上顶着的'危'又要变深了呢(rnm,tq!)
不写了,改\(z\)去了。

2021-07-22 08:07:49 星期四

d

分m次贪心枚举扔几个a和几个b,用堆维护b,如果a进来一个,b又把它扔了就不用计算了,否则更新最大值即可

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline ll max(ll a,ll b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100;int n,m;
	struct node{int id;ll x,y;friend bool operator <(node a,node b){return a.y==b.y?a.x>b.x:a.y>b.y;}}a[N];
	inline bool com(node a,node b){return a.x==b.x?a.y<b.y:a.x<b.x;}
	ll ans;
	inline short main(){
		int T=read();
		while(T--){
			std::priority_queue<node>q;
			n=read();m=read();
			F(i,1,n)a[i].id=i,a[i].x=read(),a[i].y=read();
			std::sort(a+1,a+n+1,com);
			F(i,m+1,n)q.push(a[i]);
			ans=a[m+1].x*q.top().y;
			D(i,m,1){
				q.push(a[i]);
				if(q.top().id==a[i].id){q.pop();continue;}
				q.pop();
				ans=max(ans,a[i].x*q.top().y);
			}
			pi(ans);pn();
		}
		return 0;
	}
}
signed main(){return EMT::main();}

e

是罕见的考场上想到的解法...然而被卡小常数t掉了11pts...

用主席树,dfn为历史版本,就是一道树剖+权值线段树板子题...

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline void deb(){pf("debug\n");}
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100,maxn=1e9+100;int head[N],co,n,len,k,Q,type,a[N],s[N<<2],b[N<<2],cnt,time[N],ti,lans;
	struct node{int next,to;}e[N<<1];inline void add(int next,int to){e[++co].next=head[next],e[co].to=to,head[next]=co;}
	struct qus{int r,k;std::vector<int>x;}q[310000];
	struct zxs{
		int rt[N],sum[N*40],tot,ls[N*40],rs[N*40];
		inline void insert(int x,int &y,int l,int r,int v){
			y=++tot;sum[y]=sum[x]+1;if(l==r)return;
			int mid=(l+r)>>1;
			if(v<=mid){rs[y]=rs[x];insert(ls[x],ls[y],l,mid,v);}
			else{ls[y]=ls[x];insert(rs[x],rs[y],mid+1,r,v);}
		}
		inline int querymax(int x,int y,int l,int r,int ql,int qr){
			if(sum[y]-sum[x]==0)return 0;
			if(l==r)return l;
			if(l>=ql&&r<=qr){
				int mid=(l+r)>>1;
				if(sum[rs[y]]-sum[rs[x]])return querymax(rs[x],rs[y],mid+1,r,ql,qr);
				else return querymax(ls[x],ls[y],l,mid,ql,qr);
			}else{
				int mid=(l+r)>>1;
				if(qr<=mid)return querymax(ls[x],ls[y],l,mid,ql,qr);
				if(ql>mid)return querymax(ls[x],ls[y],mid+1,r,ql,qr);
				return max(querymax(ls[x],ls[y],l,mid,ql,mid),querymax(rs[x],rs[y],mid+1,r,mid+1,qr));
			}
		}
		inline int querymin(int x,int y,int l,int r,int ql,int qr){
			if(sum[y]-sum[x]==0)return maxn;
			if(l==r)return l;
			if(l>=ql&&r<=qr){
				int mid=(l+r)>>1;
				if(sum[ls[y]]-sum[ls[x]])return querymin(ls[x],ls[y],l,mid,ql,qr);
				else return querymin(rs[x],rs[y],mid+1,r,ql,qr);
			}else{
				int mid=(l+r)>>1;
				if(qr<=mid)return querymin(ls[x],ls[y],l,mid,ql,qr);
				if(ql>mid)return querymin(rs[x],rs[y],mid+1,r,ql,qr);
				return min(querymin(ls[x],ls[y],l,mid,ql,mid),querymin(rs[x],rs[y],mid+1,r,mid+1,qr));
			}
		}
		inline void build(){
			F(i,1,n)insert(rt[i-1],rt[i],1,len,a[time[i]]);
		}
	}zx;
	struct tp{
		struct tree{int top,fa,deep,dfn,son,size;}t[N];
		inline void dfs1(int k,int fa){
			t[k].size=1;t[k].son=-1;
			for(register int i=head[k],j;i;i=e[i].next){
				j=e[i].to;if(j==fa)continue;
				t[j].fa=k;t[j].deep=t[k].deep+1;
				dfs1(j,k);t[k].size+=t[j].size;
				if(t[k].son==-1||t[t[k].son].size<t[j].size)t[k].son=j;
			}
		}
		inline void dfs2(int k,int tp){
			t[k].top=tp;t[k].dfn=++ti;time[ti]=k;
			if(t[k].son==-1)return;
			dfs2(t[k].son,tp);
			for(register int i=head[k];i;i=e[i].next)
				if(e[i].to!=t[k].son&&e[i].to!=t[k].fa)
					dfs2(e[i].to,e[i].to);
		}
		inline int getans(int x,int y,int r){
			int fx=t[x].top,fy=t[y].top,maxans=0,minans=maxn;
			while(fx!=fy){
				if(t[fx].deep>=t[fy].deep){
					maxans=max(maxans,zx.querymax(zx.rt[t[fx].dfn-1],zx.rt[t[x].dfn],1,len,1,r));
					minans=min(minans,zx.querymin(zx.rt[t[fx].dfn-1],zx.rt[t[x].dfn],1,len,r+1,len));
					x=t[fx].fa;
				}else{
					maxans=max(maxans,zx.querymax(zx.rt[t[fy].dfn-1],zx.rt[t[y].dfn],1,len,1,r));
					minans=min(minans,zx.querymin(zx.rt[t[fy].dfn-1],zx.rt[t[y].dfn],1,len,r+1,len));
					y=t[fy].fa;
				}fx=t[x].top,fy=t[y].top;
			}
			if(t[x].deep>=t[y].deep){
				maxans=max(maxans,zx.querymax(zx.rt[t[y].dfn-1],zx.rt[t[x].dfn],1,len,1,r));
				minans=min(minans,zx.querymin(zx.rt[t[y].dfn-1],zx.rt[t[x].dfn],1,len,r+1,len));
			}else{
				maxans=max(maxans,zx.querymax(zx.rt[t[x].dfn-1],zx.rt[t[y].dfn],1,len,1,r));
				minans=min(minans,zx.querymin(zx.rt[t[x].dfn-1],zx.rt[t[y].dfn],1,len,r+1,len));
			}int ans=maxn;
			if(maxans){
				ans=min(ans,s[r]-s[maxans]);
			}if(minans!=maxn){
				ans=min(ans,s[minans]-s[r]);
			}return ans;
		}
		inline void prepare(){
			dfs1(1,0);dfs2(1,1);
			zx.build();
		}
	}sp;
	inline short main(){
		//file();
		n=read(),Q=read(),type=read();if(!Q)return 0;
		F(i,1,n){a[i]=read();s[++cnt]=a[i];}
		F(i,1,n-1){int x=read(),y=read();add(x,y);add(y,x);}
		F(i,1,Q){
			q[i].r=read(),q[i].k=read();cnt++;s[cnt]=b[i]=q[i].r;
			F(j,1,q[i].k)q[i].x.push_back(read());
		}
		std::sort(s+1,s+cnt+1);len=std::unique(s+1,s+cnt+1)-s-1;
		F(i,1,n)a[i]=std::lower_bound(s+1,s+len+1,a[i])-s;
		F(i,1,Q)b[i]=std::lower_bound(s+1,s+len+1,b[i])-s;
		sp.prepare();
		F(i,1,Q){
			F(j,1,q[i].k)
				q[i].x[j-1]=(q[i].x[j-1]-1+lans*type)%n+1;
			lans=maxn;
			F(j,0,(int)q[i].x.size()-1)
				lans=min(lans,sp.getans(q[i].x[0],q[i].x[j],b[i]));
			pi(lans);pn();
		}
		return 0;
	}
}
signed main(){return EMT::main();}

f

这就去改
2021-07-22 14:30:01 星期四

改完f了,还有10mins考试

先meet in middle,处理k/2和k-k/2的部分,

二分答案找出符合条件的逆序对个数,

二元组(a,b),(x,y)满足相加为(a+x,b+y<<(k/2))

然后通过求出的个数来推得序号

不知道为什么我的程序把id求对了个数反而求错了,于是套了个归并排序的板子求了个个数。

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	#define int long long
	inline int read()
	{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=3e6+100;
	int son[N<<2][2],size[N<<2],val[35][2],tot,k1,rt,n,p,k,k2,a[N],r[N];
	struct node{ll val,id;friend bool operator <(node a,node b){return a.val==b.val?a.id<b.id:a.val<b.val;}}s1[N],s2[N];
	inline int check(node x){
		ll v=0;
		F(i,0,(1<<k1)-1)v+=std::upper_bound(s2,s2+(1<<k2),(node){x.val-s1[i].val,x.id-(s1[i].id<<k2)})-s2;
		return v;
	}
	void ins(int &x,int va,int deep){
		if(!x)x=++tot;size[x]++;
		if(deep==-1)return;
		int v=(va>>deep)&1;
		ins(son[x][v],va,deep-1);
		val[deep][v]+=size[son[x][v^1]];
	}
	int step;
	void pai(int s,int t)
	{
		int m,i,k,j;if(s==t)return;
		m=(s+t)>>1;pai(s,m);pai(m+1,t);
		i=s;j=m+1;k=s;
		while(i<=m&&j<=t){if(a[i]<=a[j]){r[k]=a[i];i++;k++;}else{step+=(m-i+1);r[k]=a[j];j++;k++;}}
		while(i<=m){r[k]=a[i];i++;k++;}
		while(j<=t){r[k]=a[j];j++;k++;}
		for(int i=s;i<=t;i++)a[i]=r[i];
	}
	inline short main(){
	//	file();
		n=read(),k=read(),p=read();k1=k>>1;k2=k-k1;
		F(i,1,n)ins(rt,a[i]=read(),k-1);
		F(i,0,(1<<k1)-1){s1[i].id=i;F(j,0,k1)s1[i].val+=val[j+k2][(i>>j)&1];}
		F(i,0,(1<<k2)-1){s2[i].id=i;F(j,0,k2)s2[i].val+=val[j][(i>>j)&1];}
		std::sort(s1,s1+(1<<k1));std::sort(s2,s2+(1<<k2));
		int l=0,r=n*(n-1)/2,ans=0;
		while(l<=r){
			int mid=(l+r)>>1;
			if(check((node){mid,0})<p)ans=mid,l=mid+1;
			else r=mid-1;
		}
		l=0,r=(1<<k)-1;int ans2=0;
		while(l<=r){
			int mid=(l+r)>>1;
			if(check((node){ans,mid})<p)l=mid+1;
			else ans2=mid,r=mid-1;
		}
		F(i,1,n)a[i]^=ans2;
		pai(1,n);
		pi(step);pi(ans2);
		return 0;
	}
}
signed main(){return EMT::main();}

考试了考试了
2021-07-25 14:47:21 星期日
放假回来了,困展了(然而根本没VAN够

把每一个询问的\(l,r,l-1,r+1\)以及1离散化出来,简单的线段树修改即可

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline ll read()
	{ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=1e7+100;int m;ll l[N],r[N],s[N],cnt;
	struct seg{
		int lz[N<<2],num[N<<2];
		inline void cg(int x,int y,int l,int r){
			if(!lz[x]){
				if(y==1)num[x]=0,lz[x]=1;
				else if(y==2)num[x]=r-l+1,lz[x]=2;
				else num[x]=(r-l+1)-num[x],lz[x]=3;
			}else{
				if(y==1)num[x]=0,lz[x]=1;
				if(y==2)num[x]=r-l+1,lz[x]=2;
				if(y==3){
					if(lz[x]==1)lz[x]=2,num[x]=r-l+1;
					else if(lz[x]==2)lz[x]=1,num[x]=0;
					else lz[x]=0,num[x]=(r-l+1)-num[x];
				}
			}
		}
		inline void down(int p,int l,int r){
			if(lz[p]){
				int mid=(l+r)>>1;
				cg(p<<1,lz[p],l,mid);
				cg(p<<1|1,lz[p],mid+1,r);
				lz[p]=0;
			}
		}
		inline void up(int p){num[p]=num[p<<1]+num[p<<1|1];}
		inline void build(int p,int l,int r){
			if(l==r){num[p]=1;return;}
			int mid=(l+r)>>1;
			build(p<<1,l,mid);build(p<<1|1,mid+1,r);
			up(p);
		}
		inline void change(int p,int l,int r,int ql,int qr,int opt){
			if(l>=ql&&r<=qr){
				cg(p,opt,l,r);
				return;
			}down(p,l,r);int mid=(l+r)>>1;
			if(qr<=mid)change(p<<1,l,mid,ql,qr,opt);
			else if(ql>mid)change(p<<1|1,mid+1,r,ql,qr,opt);
			else change(p<<1,l,mid,ql,mid,opt),change(p<<1|1,mid+1,r,mid+1,qr,opt);
			up(p);
		}
		inline int ask(int p,int l,int r){
			if(l==r)return l;
			int mid=(l+r)>>1;down(p,l,r);
			if(num[p<<1])return ask(p<<1,l,mid);
			else return ask(p<<1|1,mid+1,r);
		}
	}segm;
	int opt[N];
	inline short main(){
		m=read();
		F(i,1,m){
			opt[i]=read();l[i]=read(),r[i]=read();
			s[++cnt]=l[i],s[++cnt]=l[i]-1;
			if(l[i]-1==0)cnt--;
			s[++cnt]=r[i],s[++cnt]=r[i]+1;
		}s[++cnt]=1;
		std::sort(s+1,s+cnt+1);
		int len=std::unique(s+1,s+cnt+1)-s-1;
		F(i,1,m)l[i]=std::lower_bound(s+1,s+len+1,l[i])-s,r[i]=std::lower_bound(s+1,s+len+1,r[i])-s;
		segm.build(1,1,len);
		F(i,1,m){
			segm.change(1,1,len,l[i],r[i],opt[i]);
			pi(s[segm.ask(1,1,len)]);pn();
		}
		return 0;
	}
}
signed main(){return EMT::main();}

强者wtz打表发现本题可用三分水过,于是前缀和预处理,枚举用几个两个都喜欢的即可

Code
%: pragma GCC optimize("Ofast")
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read()
	{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline ll min(ll a,ll b){return a<b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=2e5+100;int n,m,k,cnt[5],x[5][N];bool can[N][4];
	struct pt{int v,id;friend bool operator <(pt a,pt b){return a.v<b.v;}}p[N];
	inline void die(){pi(-1);exit(0);}
	ll pre[5][N],ans=0x7fffffffffffffff;
	const ll maxn=0x7fffffffffffffff;
	inline ll check(int vv){
		int res=k-vv;ll ne=pre[3][vv];int tot=0;
		ne+=pre[1][res];tot+=res*2+vv;if(tot>m)return maxn;
		ne+=pre[2][res];int key1=res+1,key2=res+1,key4=1;
		while(tot<m){
			ll v1=key1<=cnt[1]?x[1][key1]:maxn,v2=key2<=cnt[2]?x[2][key2]:maxn;
			ll v4=key4<=cnt[4]?x[4][key4]:maxn;
			ll mi=min(min(v1,v2),v4);
			ne+=mi;tot++;
			if(v1==mi)key1++;
			else if(v2==mi)key2++;
			else key4++;
		}
		ans=min(ans,ne);return ne;
	}
	inline short main(){
		//file();
		n=read(),m=read(),k=read();
		if(m>n)die();
		F(i,1,n)p[i].v=read(),p[i].id=i;
		cnt[1]=read();if(cnt[1]<k)die();
		F(i,1,cnt[1])can[read()][1]=1;
		cnt[2]=read();if(cnt[2]<k)die();
		int both=0;
		F(i,1,cnt[2]){int x=read();can[x][2]=1;if(can[x][1])can[x][3]=1,both++;}
		if(m<k*2-both)die();
		std::sort(p+1,p+n+1);cnt[1]=cnt[2]=cnt[3]=0;
		F(i,1,n){
			if(can[p[i].id][3])x[3][++cnt[3]]=p[i].v;
			else if(can[p[i].id][1])x[1][++cnt[1]]=p[i].v;
			else if(can[p[i].id][2])x[2][++cnt[2]]=p[i].v;
			else x[4][++cnt[4]]=p[i].v;
		}
		F(i,1,4)F(j,1,cnt[i])pre[i][j]=pre[i][j-1]+x[i][j];
		int l=0,r=cnt[3];
		while(r-l>10){
			int mid1=l+(r-l)/3,mid2=r-(r-l)/3;
			if(check(mid1)<check(mid2))r=mid2;
			else l=mid1;
		}
		F(i,l,r)check(i);
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}


玄学枚举集合内容是否有不符合条件的,直接跳就OK了

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read()
	{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100,M=410;
	int n,m,x[N],y[N],w[M][M],g[M];
	inline short main(){
		n=read(),m=read();
		F(i,1,n)w[i][i]=1,g[i]=1;
		F(i,1,m)x[i]=read(),y[i]=read();
		F(i,1,n)
			D(j,m,1){
				if(w[i][x[j]]&&w[i][y[j]])g[i]=0;
				else if(w[i][x[j]])w[i][y[j]]=1;
				else if(w[i][y[j]])w[i][x[j]]=1;
			}
		int ans=0;
		F(i,1,n){
			F(j,i+1,n){
				if(!g[i]||!g[j])continue;
				bool fl=1;
				F(k,1,n)if(w[i][k]&&w[j][k]){fl=0;break;}
				if(fl)ans++;
			}
		}
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

2021-07-28 20:06:02 星期三
终于有时间写boke了...然而还是咕咕掉了两个题

matrix

状压dp。设\(f_{i,j,k}\)表示第\(i\)行,被上一行和自己覆盖的状态为\(j\),这一行按钮状态为\(k\)的最小花费,显然本行状态能够从上一行状态能够被本行按钮补全的转移过来,

于是dp柿子就出来了。
卡了卡小常,喜提最优解~

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	int f[11][1<<10][1<<10],n,m,st[15],w[15][15],v[15][1<<10];char s[15][15];const int maxn=0x7f7f7f7f;
	inline short main(){
		n=read(),m=read();;;;;;
		F(i,1,n)F(j,0,(1<<m)-1)F(k,0,(1<<m)-1)f[i][j][k]=maxn;
		F(i,1,n){scanf("%s",s[i]+1);F(j,1,m)st[i]|=(s[i][j]=='1')<<(j-1);}
		F(i,1,n)F(j,1,m)w[i][j]=read();
		int tot=(1<<m)-1;
		F(i,1,n)F(j,1,m)F(k,0,(1<<m)-1)if(k&(1<<(j-1)))v[i][k]+=w[i][j];
		F(j,0,(1<<m)-1)f[1][st[1]|j|((j<<1)&tot)|(j>>1)][j]=v[1][j];
		F(i,2,n)
			F(j,st[i-1],(1<<m)-1)
				if((j&st[i-1])==st[i-1])
				F(k,0,(1<<m)-1)
					if(f[i-1][j][k]!=maxn)
						F(l,0,(1<<m)-1)
							if((l|j)==tot){
								int zt=st[i]|l|((l<<1)&tot)|(l>>1)|k;
								f[i][zt][l]=min(f[i][zt][l],f[i-1][j][k]+v[i][l]);
							}
		int ans=maxn;
		F(i,0,(1<<m)-1)ans=min(ans,f[n][tot][i]);
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

block

用线段树维护。考虑先放key小的,放完之后所有小于这个数权值的放置机会都少了1,相当于key--,如果有key=1的,就只能放比这个权值小的数了。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=5e5+100;int eg1[N],eg2[N],n,ans=1,len,s[N],lower[N],upper[N];const int mod=1e9+7,maxn=0x7f7f7f7f;
	struct pt{int key,val;friend bool operator <(pt a,pt b){return a.val==b.val?a.key<b.key:a.val>b.val;}}p[N];
	struct que{int key,wei;};
	inline void solve1(){
		std::sort(p+1,p+n+1);int cnt=0;
		F(i,1,n)
		if(p[i].val==p[i-1].val)ans=1ll*ans*min(i,p[i].key+cnt)%mod,cnt++;
		else ans=1ll*ans*min(i,p[i].key)%mod,cnt=1;
	}
	struct seg{
		struct tree{int lz,oldkey,key,oldwei,wei;}t[N<<2];
		inline void up(int p){
			if(t[p<<1].oldkey<=t[p<<1|1].oldkey){
				t[p].oldkey=t[p<<1].oldkey;
				t[p].oldwei=t[p<<1].oldwei;
			}else{
				t[p].oldkey=t[p<<1|1].oldkey;
				t[p].oldwei=t[p<<1|1].oldwei;
			}
			if(t[p<<1].key<=t[p<<1|1].key){
				t[p].key=t[p<<1].key;
				t[p].wei=t[p<<1].wei;
			}else{
				t[p].key=t[p<<1|1].key;
				t[p].wei=t[p<<1|1].wei;
			}
		}
		inline void down(int p){
			if(t[p].lz){
				t[p<<1].lz+=t[p].lz;
				t[p<<1|1].lz+=t[p].lz;
				t[p<<1].key+=t[p].lz;
				t[p<<1|1].key+=t[p].lz;
				t[p].lz=0;
			}
		}
		void build(int x,int l,int r){
			if(l==r){t[x].oldkey=t[x].key=p[l].key;t[x].wei=t[x].oldwei=l;return;}
			int mid=(l+r)>>1;
			build(x<<1,l,mid);build(x<<1|1,mid+1,r);
			up(x);
		}
		void change(int p,int l,int r,int ql,int qr,int v){
			if(ql>qr)return;
			if(l>=ql&&r<=qr){
				t[p].lz+=v;
				t[p].key+=v;
				return;
			}down(p);int mid=(l+r)>>1;
			if(qr<=mid)change(p<<1,l,mid,ql,qr,v);
			else if(ql>mid)change(p<<1|1,mid+1,r,ql,qr,v);
			else change(p<<1,l,mid,ql,mid,v),change(p<<1|1,mid+1,r,mid+1,qr,v);
			up(p);
		}
		void del(int p,int l,int r,int x){
			if(l==r){t[p].key=t[p].oldkey=maxn;return;}
			down(p);int mid=(l+r)>>1;
			if(x<=mid)del(p<<1,l,mid,x);else del(p<<1|1,mid+1,r,x);
			up(p);
		}
		que ask(int p,int l,int r,int ql,int qr){
			if(l>=ql&&r<=qr){
				que x;
				x.key=t[p].oldkey;
				x.wei=t[p].oldwei;
				return x;
			}
			int mid=(l+r)>>1;down(p);
			if(qr<=mid)return ask(p<<1,l,mid,ql,qr);
			else if(ql>mid)return ask(p<<1|1,mid+1,r,ql,qr);
			else{
				que x1=ask(p<<1,l,mid,ql,mid),x2=ask(p<<1|1,mid+1,r,mid+1,qr);
				if(x1.key<=x2.key)return x1;
				else return x2;
			}
		}
	}segm;
	inline bool com(pt a,pt b){return a.val==b.val?a.key<b.key:a.val<b.val;}
	inline void solve2(){
		std::sort(p+1,p+n+1,com);
		int fl=1;
		F(i,1,n){
			if(p[i].val!=p[i-1].val)fl=i;
			lower[i]=fl;
		}fl=n;
		D(i,n,1){
			if(p[i].val!=p[i+1].val)fl=i;
			upper[i]=fl;
		}
		segm.build(1,1,n);
		F(i,1,n){
			if(segm.t[1].key==1){
				que x=segm.ask(1,1,n,1,upper[segm.t[1].wei]);
				pi(p[x.wei].key);pi(p[x.wei].val);pn();
				segm.del(1,1,n,x.wei);
				segm.change(1,1,n,1,lower[x.wei]-1,-1);
			}else{
				que x=segm.ask(1,1,n,1,n);
				pi(p[x.wei].key);pi(p[x.wei].val);pn();
				segm.del(1,1,n,x.wei);
				segm.change(1,1,n,1,lower[x.wei]-1,-1);
			}
		}
	}
	inline short main(){
		n=read();
		F(i,1,n)p[i].key=read(),s[i]=p[i].val=read();
		solve1();
		pi(ans);pn();
		solve2();
		return 0;
	}
}
signed main(){return EMT::main();}

graph

不会,先咕掉

random

wtcl,引用lby强者的证明:

2021-07-28 20_18_25 的屏幕截图.png

ps:sm.ms上不去,图裂了别怪我(逃

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define int long long
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int mod=998244353;int n;
	inline int random(int x){
		return (rand()*rand()%x+x)%x;
	}
	inline ll ksm(int a,int b){
		ll ans=1;
		while(b){
			if(b&1)ans=1ll*ans*a%mod;
			a=1ll*a*a%mod;
			b>>=1;
		}return ans;
	}
	inline short main(){
		srand(time(0));
		int T=read();
		while(T--){
			int x=read()%mod;
			pi(1ll*(x*x-1+mod)%mod*ksm(9,mod-2)%mod);pn();
		}
		return 0;
	}
}
signed main(){return EMT::main();}

string

以后再把n默认成字符串长度我就去死吧

把子字符串正序倒序分别插入trie树上,dfs一遍记录哈希,然后对于母串的每个位置二分最长的对应前后缀长度相乘最后加起来就是答案。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;typedef unsigned long long ull;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int mod=3e5+7,N=1e5+100,M=3e5+100;char S[M],s[M];ull hash[M],p[M];int lens,len,n;ll pre[M],end[M];
	struct hash_table{
		int head[mod],co;
		struct node{
			int next;ll val;ull key;
		}e[2000000];
		inline int f(ull x){return x%mod;}
		inline ll find(ull x){
			for(register int i=head[f(x)];i;i=e[i].next)
				if(e[i].key==x)return e[i].val;
			return -1;
		}
		inline void add(ull x,ll val){
			e[++co].next=head[f(x)],e[co].key=x,e[co].val=val,head[f(x)]=co;
		}
		inline void change(ull x,ll val){
			for(register int i=head[f(x)];i;i=e[i].next)
				if(e[i].key==x){e[i].val=val;return;}
			add(x,val);
		}
	};
	struct tr{
		ll w[N<<2];int son[N<<2][27],tot,rt;
		hash_table hs;
		inline void insert(int &p,int dep){
			if(!p)p=++tot;
			if(p!=rt)w[p]++;
			if(dep==len)return;
			insert(son[p][s[dep+1]-'a'],dep+1);
		}
		inline void dfs(int P,ll v,ull hash,int dep){
			if(!P)return;
			w[P]+=v;hs.change(hash,w[P]);
			F(i,0,25)dfs(son[P][i],w[P],dep>=0?hash+(i+1)*p[dep]:hash*131+i+1,dep>=0?dep+1:-1);
		}
	}st,ed;
	inline ull gethash(int l,int r){return hash[r]-hash[l-1]*p[r-l+1];}
	inline short main(){
		p[0]=1;
		scanf("%s",S+1);lens=strlen(S+1);
		F(i,1,lens)p[i]=p[i-1]*131;
		F(i,1,lens)hash[i]=hash[i-1]*131+S[i]-'a'+1;
		n=read();
		F(i,1,n){
			scanf("%s",s+1);len=strlen(s+1);
			st.insert(st.rt,0);
			std::reverse(s+1,s+len+1);
			ed.insert(ed.rt,0);
		}st.dfs(st.rt,0,0,-1);ed.dfs(ed.rt,0,0,0);
		st.hs.change(0,0);ed.hs.change(0,0);
		F(i,1,lens){
			int l=0,r=i+1,ans=0;
			while(l<=r){
				int mid=(l+r)>>1;
				if(ed.hs.find(gethash(i-mid+1,i))!=-1)l=mid+1,ans=mid;
				else r=mid-1;
			}
			end[i+1]=ed.hs.find(gethash(i-ans+1,i));
		}
		F(i,1,lens){
			int l=0,r=lens-i,ans=0;
			while(l<=r){
				int mid=(l+r)>>1;
				if(st.hs.find(gethash(i,i+mid-1))!=-1)l=mid+1,ans=mid;
				else r=mid-1;
			}
			pre[i]=st.hs.find(gethash(i,i+ans-1));
		}
		ll ans=0;
		F(i,1,lens)ans+=pre[i]*end[i];
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

queen

仅四项多项式长至整整一行,半个机房骂声一片,这究竟是道德的沦丧,还是人性的泯灭?
欢迎收看今日的《queen说法》。

首先所有情况都可以是整整一行、一列、一条斜线。
这样算出的

\[pre=2(n+m+1)C_{min(n,m)}^{k}-2kC_{min(n,m)+1}^{k+1}+nC_{m}^{k}+mC_{n}^{k} \]

其中由于n,m太大,要用lucas定理求得。

另外本题中用到了从来都没有用到过的

\[\sum_{i=1}^{n}i^2=i(i+1)(i*2+1)/6 \]

当然除法要用逆元

  1. k>5||k==2时,只存在\(pre\)

  2. k==1 显然\(nm\)不包括\(pre\)

  3. k==3

  4. k==5
    2021-07-28 20_44_35 的屏幕截图.png

  5. k==4
    是3和5的缝合版本改改系数就ok了。

\(min(n,m)=t\) 到i平方和设为\(pfh(i)\),等差数列和设为\(dch(i)\)
其中:

\[\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}min(i,j)-1=\sum\limits_{i=1}^{t}i(m-i)+\sum\limits_{i=1}^{t}i(n-i)+\sum\limits_{i=1}^{t}i-nm \]

也就是:

\[\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}min(i,j)-1=dch(t)*(n+m+1)-2pfh(i)-mn \]

另外:

\[\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}C_{min(i,j)-1}^{k-1}=(n+m+1)*C_{t}^{k}-2*k*C_{t+1}^{k+1} \]

这样就可以\(O(1)\)求了

好像是这几道里题解写的最多的了,好累不写了

Code


%: pragma GCC optimize("O3")
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline ll min(ll a,ll b){return a<b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}const int mod=3e5+7;
	ll n,m,k;int jc[mod+100];
	inline int ksm(int a,int b){
		int ans=1;
		while(b){
			if(b&1)ans=1ll*ans*a%mod;
			a=1ll*a*a%mod;
			b>>=1;
		}return ans;
	}
	inline int c(int n,int m){
		if(n<m)return 0;
		return 1ll*jc[n]*ksm(jc[m],mod-2)%mod*ksm(jc[n-m],mod-2)%mod;
	}
	inline ll lucas(ll n,ll m){
		if(!n)return 1;if(n<m)return 0;
		return 1ll*c(n%mod,m%mod)*lucas(n/mod,m/mod)%mod;
	}
	inline ll pfh(ll x){
		return x%mod*((x+1)%mod)%mod*((x*2+1)%mod)%mod*ksm(6,mod-2)%mod;
	}
	inline short main(){
		int T=read();
		jc[0]=1;
		F(i,1,mod)jc[i]=1ll*jc[i-1]*i%mod;
		while(T--){
			n=read(),m=read(),k=read();ll t=min(n,m),x=(t-1)>>1;
			ll pre=(2*((n%mod+m%mod+1)%mod*lucas(min(n,m),k)%mod-2*k%mod*lucas(min(n,m)+1,k+1)%mod+mod)%mod+(n%mod)*lucas(m,k)%mod+(m%mod)*lucas(n,k)%mod)%mod;
			if(k>5||k==2)pi(pre);
			else if(k==1)pi((m%mod)*(n%mod)%mod);
			else if(k==3){
				ll D1=4*((1+t)%mod*(t%mod)%mod*ksm(2,mod-2)%mod*(((n%mod)+(m%mod)+1)%mod)%mod-2*pfh(t)%mod-(m%mod)*(n%mod)%mod)%mod;
				ll D2;
				x=min(m,n/2)%mod;
				D2=(((n%mod)*(m%mod)%mod*(x%mod)%mod+2*pfh(x)%mod-(2*m%mod+n%mod)%mod*((1+x)%mod)%mod*(x%mod)%mod*ksm(2,mod-2)%mod+mod)%mod*2%mod+mod)%mod;
				x=min(n,m/2)%mod;
				D2=(D2+((n%mod)*(m%mod)%mod*(x%mod)%mod+2*pfh(x)%mod-(2*n%mod+m%mod)%mod*((1+x)%mod)%mod*(x%mod)%mod*ksm(2,mod-2)%mod+mod)%mod*2%mod+mod)%mod;
				pi((pre+D1+D2+mod)%mod);
			}
			else if(k==4){
				ll D2=5*((x%mod)*(m%mod)%mod*(n%mod)%mod-(1+x)%mod*(x%mod)%mod*((m%mod+n%mod)%mod)%mod+2*(x%mod)*((x+1)%mod)%mod*((2*x+1)%mod)%mod*ksm(3,mod-2)%mod)%mod;
				x=min(m,n/2)%mod;
				ll D1=(((n%mod)*(m%mod)%mod*(x%mod)%mod+2*pfh(x)%mod-(2*m%mod+n%mod)%mod*((1+x)%mod)%mod*(x%mod)%mod*ksm(2,mod-2)%mod+mod)%mod*2%mod+mod)%mod;
				x=min(n,m/2)%mod;
				D1=(D1+((n%mod)*(m%mod)%mod*(x%mod)%mod+2*pfh(x)%mod-(2*n%mod+m%mod)%mod*((1+x)%mod)%mod*(x%mod)%mod*ksm(2,mod-2)%mod+mod)%mod*2%mod+mod)%mod;
				ll D3=((1+t)%mod*(t%mod)%mod*ksm(2,mod-2)%mod*(((n%mod)+(m%mod)+1)%mod)%mod-2*pfh(t)%mod-(m%mod)*(n%mod)%mod)%mod;
				pi((pre+D1+D2+D3+mod)%mod);
			}
			else
		pi((mod+pre+2*((x%mod)*(m%mod)%mod*(n%mod)%mod-(1+x)%mod*(x%mod)%mod*((m%mod+n%mod)%mod)%mod+2*(x%mod)*((x+1)%mod)%mod*((2*x+1)%mod)%mod*ksm(3,mod-2)%mod))%mod);
			pn();
		}
		return 5;
	}
}
signed main(){return EMT::main();}

下面这场考试抱灵了...我还是太弱了

神炎皇

2021-07-28 21_02_34 的屏幕截图.png
于是线性筛欧拉函数\(\sqrt{n}\)枚举即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(ll á){pf("%lld ",á);}inline void pn(){pf("\n");}
	const int N=1e7+100;
	int n,phi[N],prime[N],cnt;bool is[N];
	inline void shai(int n){
		F(i,2,n){
			if(!is[i]){
				prime[++cnt]=i;
				phi[i]=i-1;
			}
			for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
				is[i*prime[j]]=1;
				if(i%prime[j]==0){
					phi[i*prime[j]]=phi[i]*prime[j];
					break;
				}else phi[i*prime[j]]=phi[i]*(prime[j]-1);
			}
		}
	}
	ll ans;
	inline short main(){
		n=read();int t=sqrt(n);
		shai(sqrt(n));
		F(i,2,t)ans+=1ll*n/(1ll*i*i)*(1ll*phi[i]);
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

降雷皇

用树状数组维护长度最大值和数目即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	const int mod=123456789;
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100;
	int n,s[N],a[N],len;
	struct node{int len,val;}p[N];
	inline node ask(int x){
		node ans;
		ans.len=0;ans.val=1;
		for(;x;x-=x&-x)if(ans.len==p[x].len)(ans.val+=p[x].val)%=mod;
		else if(ans.len<p[x].len)ans.val=p[x].val%mod,ans.len=p[x].len;
		return ans;
	}
	inline void change(int x,node v){
		for(;x<=len;x+=x&-x){
			if(p[x].len==v.len)(p[x].val+=v.val)%=mod;
			else if(p[x].len<v.len)p[x].len=v.len,p[x].val=v.val%mod;
		}
	}
	inline short main(){
		n=read();int tp=read();
		F(i,1,n)a[i]=s[i]=read();
		std::sort(s+1,s+n+1);len=std::unique(s+1,s+n+1)-s-1;
		F(i,1,n)a[i]=std::lower_bound(s+1,s+len+1,a[i])-s;
		F(i,1,n){
			node x=ask(a[i]-1);x.len++;
			change(a[i],x);
		}
		if(tp){
			node x=ask(len);
			pi(x.len);pn();pi(x.val);
		}else pi(ask(len).len);
		return 0;
	}
}
signed main(){return EMT::main();}

幻魔皇

再亿次引用强者lby的证明:
2021-07-28 21_08_19 的屏幕截图.png

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=5e3+10;
	int n,fb[N],dp[N][N<<1],ans[N<<1];const int mod=123456789;
	inline short main(){
		n=read();
		fb[1]=fb[2]=1;
		F(i,3,n)fb[i]=(0ll+fb[i-2]+fb[i-1])%mod;
		F(i,2,n){
			F(j,1,n<<1)dp[i][j]=(0ll+dp[i][j]+dp[i-1][j])%mod;
			F(j,3,n)dp[max(i,j)][i+j]=(0ll+dp[max(i,j)][i+j]+1ll*fb[i-1]*fb[j-2]%mod)%mod;
		}
		F(i,2,n){
			F(j,5,(n-i)<<1)ans[j]=(0ll+ans[j]+1ll*fb[i-1]*dp[n-i][j]%mod)%mod;
			F(j,i+2,n)ans[j-i+1]=(0ll+ans[j-i+1]+1ll*fb[j-i-1]*fb[i-1]%mod)%mod;
			F(j,i+2,n)ans[j-i]=(0ll+ans[j-i]+1ll*fb[j-i-1]*fb[i-2]%mod)%mod;
		}
		F(i,3,n)ans[i-1]=(0ll+ans[i-1]+fb[i-2])%mod;
		F(i,1,n<<1)pi(ans[i]);
		return 0;
	}
}
signed main(){return EMT::main();}

牛半仙的妹子图

求到每种颜色的最小需要的忍受度,对于每个l和r对每个颜色O(600)枚举暴力判断即可。

Code
#include<bits/stdc++.h>
using namespace std;
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define int long long
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=5e5+100,M=5e5+100,maxn=0x7f7f7f7f;
	int n,m,Q,X,head[N],co,c[N],s[M],len,opt,dis[N],dio[N],lans,mod;bool v[N];
	struct node{
		int next,to,w;
	}e[M<<1];
	std::priority_queue< pair<int,int> >q;
	inline void add(int next,int to,int w){e[++co].next=head[next],e[co].to=to,e[co].w=w,head[next]=co;}
	inline void dj(int k){
		dis[k]=0;q.push(make_pair(0,k));
		while(q.size()){
			int x=q.top().second;q.pop();
			if(v[x])continue;v[x]=1;
			for(register int i=head[x];i;i=e[i].next){
				if(dis[e[i].to]>max(e[i].w,dis[x])){
					dis[e[i].to]=max(e[i].w,dis[x]);
					q.push(make_pair(-dis[e[i].to],e[i].to));
				}
			}
		}
	}
	inline short main(){
		//file();
		memset(dis,0x7f,sizeof(dis));
		memset(dio,0x7f,sizeof(dio));
		int maxc=0;
		n=read(),m=read(),Q=read(),X=read(),opt=read();if(opt)mod=read();
		F(i,1,n)c[i]=read();
		F(i,1,m){
			int x=read(),y=read(),z=read();
			add(x,y,z);add(y,x,z);
		}
		dj(X);
		//F(i,1,n)pi(dis[i]),pn();
		F(i,1,n)maxc=max(maxc,c[i]),dio[c[i]]=min(dio[c[i]],dis[i]);
		F(i,1,Q){
			int l=read(),r=read();
			if(opt){l=(l^lans)%mod+1,r=(r^lans)%mod+1;if(l>r)swap(l,r);}
			if(l>r)swap(l,r);
			lans=0;
			F(j,1,maxc){
				if(dio[j]>r||dio[j]==maxn)continue;
				lans+=r-max(dio[j],l)+1;
			}pi(lans);pn();
		}
		return 0;
	}
}
signed main(){return EMT::main();}

牛半仙的妹子Tree

玄学复杂度...(upd in 不知道什么时候:被二位队爷的hack数据卡掉了...(虽然我也把自己卡了)).

用栈存被感染的点和对应时间。
加入一个点时遍历栈中是否有能够覆盖这个点的,有就不加了。

查询时也一样。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100;int co,head[N],ti;
	struct node{int id,tim;};
	struct edg{int next,to;}e[N<<1];
	struct tp{
		struct tre{int dep,son,top,size,fa;}t[N];
		void dfs1(int k,int f){
			t[k].size=1;
			for(register int i=head[k];i;i=e[i].next){
				if(e[i].to==f)continue;
				t[e[i].to].fa=k;t[e[i].to].dep=t[k].dep+1;
				dfs1(e[i].to,k);t[k].size+=t[e[i].to].size;
				if(t[t[k].son].size<=t[e[i].to].size)t[k].son=e[i].to;
			}
		}
		void dfs2(int k,int tp){
			t[k].top=tp;
			if(!t[k].son)return;
			dfs2(t[k].son,tp);
			for(register int i=head[k];i;i=e[i].next)
				if(e[i].to!=t[k].son&&e[i].to!=t[k].fa)
					dfs2(e[i].to,e[i].to);
		}
		inline int getlca(int x,int y){
			int fx=t[x].top,fy=t[y].top;
			while(fx!=fy){
				if(t[fx].dep>=t[fy].dep)x=t[fx].fa;
				else y=t[fy].fa;
				fx=t[x].top;fy=t[y].top;
			}
			if(t[x].dep>=t[y].dep)return y;
			else return x;
		}
	}trp;
	inline int dis(int x,int y){return trp.t[x].dep+trp.t[y].dep-2*trp.t[trp.getlca(x,y)].dep;}
	inline void add(int next,int to){e[++co].next=head[next],e[co].to=to,head[next]=co;}
	int n,m,top;node s[N];
	inline void yes(){pf("orzFsYo\n");}
	inline void no(){pf("wrxcsd\n");}
	inline short main(){
		n=read(),m=read();
		F(i,1,n-1){
			int x=read(),y=read();
			add(x,y);add(y,x);
		}trp.dfs1(1,0);trp.dfs2(1,1);
		F(i,1,m){
			int opt=read(),x=read();
			if(opt==1){
				bool fl=1;
				F(j,1,top)
					if(dis(s[j].id,x)<=i-s[j].tim)
						{fl=0;break;}
				if(fl)s[++top]=node{x,i};
			}else if(opt==2)top=0;
			else{
				bool fl=1;
				F(j,1,top)
					if(dis(s[j].id,x)<=i-s[j].tim)
						{fl=0;break;}
				if(fl)yes();
				else no();
			}
		}
		return 0;
	}
}
signed main(){return EMT::main();}

牛半仙的妹子序列

用线段树维护极长上升子序列,lv存满足右子树条件下左子树的sum,val存最大下标,num存数目。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=2e5+100,mod=998244353;
	int n,a[N],f[N];
	struct dp{int val,num;};
	struct tree{
		int val[N<<2],num[N<<2],lv[N<<2];
		inline int clac(int p,int v,int l,int r){
			if(l==r)return val[p]>v?num[p]:0;
			int mid=(l+r)>>1;
			if(val[p<<1|1]<=v)return clac(p<<1,v,l,mid);
			else return (lv[p]+clac(p<<1|1,v,mid+1,r))%mod;
		}
		inline void up(int p,int l,int r){
			int mid=(l+r)>>1;
			lv[p]=clac(p<<1,val[p<<1|1],l,mid);
			val[p]=max(val[p<<1],val[p<<1|1]);
			num[p]=(num[p<<1]+num[p<<1|1])%mod;
		}
		inline void update(int p,int l,int r,int x,int v,int t){
			if(l==r){val[p]=v;num[p]=t;return;}
			int mid=(l+r)>>1;
			if(x<=mid)update(p<<1,l,mid,x,v,t);
			else update(p<<1|1,mid+1,r,x,v,t);
			up(p,l,r);
		}
		inline dp ask(int p,int l,int r,int x){
			if(l==r)return dp{0,0};
			int mid=(l+r)>>1;
			if(x<=mid)return ask(p<<1,l,mid,x);
			else{
				dp t=ask(p<<1|1,mid+1,r,x);
				(t.num+=clac(p<<1,t.val,l,mid))%=mod;
				t.val=max(t.val,val[p<<1]);
				return t;
			}
		}
	}segm;
	inline short main(){
		n=read();
		F(i,1,n)a[i]=read();
		F(i,1,n){
			f[i]=segm.ask(1,1,n,a[i]).num;
			if(!f[i])f[i]=1;
			segm.update(1,1,n,a[i],i,f[i]);
		}
		int maxx=0,ans=0;
		D(i,n,1){
			maxx=max(maxx,a[i]);
			if(a[i]<maxx)continue;
			ans+=f[i];ans-=mod*(ans>=mod);
		}
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

2021-08-01 07:04:15 星期日

遗忘之祭仪

暴力扫描每个能够配对的第一个黑点,一定是小矩形内部的第一个黑点,暴力修改,不匹配就无解。

Code


%: pragma GCC optimize("O9")
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<bitset>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	bool S[1010][1010],s[1010][1010];
	int T;
	struct node{int x,y,a,b;};
	inline void yes(){pf("Yes\n");}
	inline void no(){pf("No\n");}
	inline void work(){
		T--;if(T==-1)exit(0);
		node x1,x2;x1.x=x1.y=x1.a=x1.b=x2.x=x2.y=x2.a=x2.b=0;
		int n=read(),m=read(),a=read(),b=read();
		F(i,1,n)F(j,1,m){char ch=getchar();while(ch!='.'&&ch!='x')ch=getchar();if(ch=='x'&&!x1.x)x1.x=i;S[i][j]=(ch=='.')?0:1;}
		F(i,1,a)F(j,1,b){char ch=getchar();while(ch!='.'&&ch!='x')ch=getchar();if(ch=='x'&&!x2.x)x2.x=i;s[i][j]=(ch=='.')?0:1;}
		D(i,n,x1.x){bool fl=0;F(j,1,m)if(S[i][j]){x1.a=i;fl=1;break;}if(fl)break;}
		F(i,1,m){bool fl=0;F(j,x1.x,x1.a)if(S[j][i]){x1.y=i;fl=1;break;}if(fl)break;}
		D(i,m,x1.y){bool fl=0;F(j,x1.x,x1.a)if(S[j][i]){x1.b=i;fl=1;break;}if(fl)break;}
		D(i,a,x2.x){bool fl=0;F(j,1,b)if(s[i][j]){x2.a=i;fl=1;break;}if(fl)break;}
		F(i,1,b){bool fl=0;F(j,x2.x,x2.a)if(s[j][i]){x2.y=i;fl=1;break;}if(fl)break;}
		D(i,b,x2.y){bool fl=0;F(j,x2.x,x2.a)if(s[j][i]){x2.b=i;fl=1;break;}if(fl)break;}
		int st=0;F(i,x2.y,x2.b)if(s[x2.x][i]){st=i-x2.y+1;break;}
		if(!x2.x)no(),work();
		F(i,x1.x,x1.a){
			F(j,x1.y,x1.b){
				if(S[i][j]){
					int sty=j-st+1,stx=i,tsx=x2.x,tsy=x2.y;
					while(1){
						if(tsy>x2.b)tsy=x2.y,tsx++,sty=j-st+1,stx++;
						if(tsx==x2.a+1)break;
						if(stx>n||sty<1)no(),work();
						if(S[stx][sty]==0&&s[tsx][tsy]==1)no(),work();else if(s[tsx][tsy]==1)S[stx][sty]=0;
						tsy++;sty++;
					}
				}
			}
		}yes();work();
	}
	inline short main(){
		T=read();
		work();
		return 0;
	}
}
signed main(){return EMT::main();}

客星璀璨之夜

考虑从上个长度转移过来,
如果上次点的是左边两个点,则这次就相当于上个长度的\(j-2\),有\(pre/i\)的概率,
如果上次点的是右边两个点,则这次就还是\(j\),有\(lst/i\)的概率,
\(1/2i\)的概率直接选中,
如果上次正好点到自己这个点,编号-1/-2,概率都是\(1/2i\)
于是柿子就出来了.

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define int long long
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int mod=998244353,N=3e3+100;
	int n,a[N*2],f[N][N*2];
	inline int ksm(int a,int b){
		int ans=1;
		while(b){
			if(b&1)ans=1ll*ans*a%mod;
			a=1ll*a*a%mod;
			b>>=1;
		}return ans;
	}
	inline short main(){
		n=read();
		F(i,1,n*2+1)a[i]=read();
		int inv2=ksm(2,mod-2);
		F(i,1,n){
			int invi=ksm(i,mod-2);
			F(j,2,i*2+1){
				int lst=(i*2-j+1)/2,pre=i-1-lst;
				if(j&1)
(f[i][j]+=1ll*f[i-1][j-1]*invi%mod*inv2%mod+1ll*f[i-1][j]*invi%mod*lst%mod+1ll*f[i-1][j-2]*pre%mod*invi%mod+1ll*f[i-1][j-2]*invi%mod*inv2%mod+1ll*invi*inv2%mod)%=mod;
				else
(f[i][j]+=1ll*f[i-1][j-1]*invi%mod*inv2%mod+1ll*f[i-1][j]*invi%mod*inv2%mod+1ll*invi*inv2%mod+1ll*f[i-1][j]*lst%mod*invi%mod+1ll*f[i-1][j-2]*pre%mod*invi%mod)%=mod;
			}
		}int ans=0;
		F(i,2,n*2+1)(ans+=f[n][i]*((a[i]-a[i-1])%mod)%mod)%=mod;
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

2021-08-03 15:06:11 星期二

最长不下降子序列

\(n<=1e6\) 时,直接暴力查询即可。
否则可以从循环节中拿出\(150\)段暴力跑LIS,剩下的每一段贡献都是1,加起来即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	#define int long long
	inline int read()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=1e6+100;
	int n,a[N],A,B,len,C,D,plc[N],l,r,S[N],ans[N],t[N];
	inline int ask(int x){int ans=0;while(x){ans=max(ans,t[x]),x-=x&-x;}return ans;}
	inline void change(int x,int v){for(;x<=D;x+=x&-x)t[x]=max(t[x],v);}
	inline void Db(){pf("debug\n");}
	inline short main(){
		n=read();a[1]=read(),A=read(),B=read(),C=read(),D=read();
		if(n<=1e6){
			F(i,2,n)a[i]=(A*a[i-1]*a[i-1]+B*a[i-1]+C)%D;
			F(i,1,n)a[i]++;
			int ans=0;
			F(i,1,n){
				int x=ask(a[i]);
				ans=max(ans,x+1);
				change(a[i],x+1);
			}
			pi(ans);
			return 0;
		}
		int key=1;
		while(!plc[a[key]]){
			plc[a[key]]=key;
			a[key+1]=(A*a[key]*a[key]+B*a[key]+C)%D;
			key++;
		}len=key-plc[a[key]];l=plc[a[key]]-1;r=((n-l)/len)*len+l+1;int cnt=(n-l)/len;
		F(i,1,len)S[i]=a[i+l];
		F(i,1,l)ans[i]=a[i];
		F(i,1,150)F(j,1,len)ans[++l]=S[j];
		F(i,r,n)ans[++l]=S[i-r+1];
		int tt=0;
		F(i,1,l){
			ans[i]++;
			int x=ask(ans[i]);
			tt=max(tt,x+1);
			change(ans[i],x+1);
		}pi(tt+cnt-150);
		return 0;
	}
}
signed main(){return EMT::main();}

最近公共祖先

修改时暴力跳父亲,将其他子树的答案用父亲权值更新,如果父亲被不同的儿子跳到两次就可以break了。查询直接查即可。

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100;
	int head[N],co;struct node{int next,to;}e[N<<1];int n,m,val[N],ti,from[N];bool v[N],blc[N],hv[N];
	inline void add(int next,int to){e[++co].next=head[next],e[co].to=to,head[next]=co;}
	struct tree1{int dfn,size,fa;}t[N];
	struct que{int opt,x;}q[N<<1];
	struct trp{
		void dfs1(int k,int fa){
			t[k].size=1;t[k].dfn=++ti;
			for(register int i=head[k];i;i=e[i].next){
				int j=e[i].to;if(j==fa)continue;
				t[j].fa=k;
				dfs1(j,k);
				t[k].size+=t[j].size;
			}
		}
	}sp;
	struct seg{
		int val[N<<2],lz[N<<2];
		inline void down(int p){
			if(lz[p]){
				val[p<<1]=max(val[p<<1],lz[p]);
				lz[p<<1]=max(lz[p<<1],lz[p]);
				val[p<<1|1]=max(val[p<<1|1],lz[p]);
				lz[p<<1|1]=max(lz[p<<1|1],lz[p]);
				lz[p]=0;
			}
		}
		void change(int p,int l,int r,int ql,int qr,int v){
			if(l>=ql&&r<=qr){
				lz[p]=max(lz[p],v);
				val[p]=max(val[p],v);
				return;
			}down(p);
			int mid=(l+r)>>1;
			if(qr<=mid)change(p<<1,l,mid,ql,qr,v);
			else if(ql>mid)change(p<<1|1,mid+1,r,ql,qr,v);
			else change(p<<1,l,mid,ql,mid,v),change(p<<1|1,mid+1,r,mid+1,qr,v);
			val[p]=max(val[p<<1],val[p<<1|1]);
		}
		int ask(int p,int l,int r,int ql,int qr){
			if(l>=ql&&r<=qr)return val[p];
			int mid=(l+r)>>1;down(p);
			if(qr<=mid)return ask(p<<1,l,mid,ql,qr);
			else if(ql>mid)return ask(p<<1|1,mid+1,r,ql,qr);
			return max(ask(p<<1,l,mid,ql,mid),ask(p<<1|1,mid+1,r,mid+1,qr));
		}
	}segm;
	inline void solve(){
		F(i,1,m){
			if(q[i].opt==1){
				int l=t[q[i].x].dfn,r=t[q[i].x].dfn+t[q[i].x].size-1;
				int now=q[i].x,f=t[now].fa;
				segm.change(1,1,n,l,r,val[q[i].x]);
				while(f){
					if(from[f]==now||from[f]==-1)break;
					if(!from[f])from[f]=now;else from[f]=-1;
					segm.change(1,1,n,t[f].dfn,l-1,val[f]);
					if(t[f].dfn+t[f].size>t[now].dfn+t[now].size)
						segm.change(1,1,n,t[now].dfn+t[now].size,t[f].dfn+t[f].size-1,val[f]);
					now=f;f=t[now].fa;l=t[now].dfn,r=t[now].dfn+t[now].size-1;
				}
			}else{
				int v=segm.ask(1,1,n,t[q[i].x].dfn,t[q[i].x].dfn);
				if(!v)v=-1;
				pi(v);pn();
			}
		}		
	}
	inline short main(){
		//file();
		n=read();m=read();
		F(i,1,n)val[i]=read();
		F(i,1,n-1){
			int x=read(),y=read();
			add(x,y);add(y,x);
		}
		sp.dfs1(1,0);
		bool op2=0,can1=1;int o1=0,o2=0;
		F(i,1,m){
			char ch=getchar();
			while(ch!='Q'&&ch!='M')ch=getchar();
			if(ch=='M')q[i].opt=1,q[i].x=read();
			else q[i].opt=2,q[i].x=read();
		}
		solve();
		return 0;
	}
}
signed main(){return EMT::main();}

完全背包问题

先读入\(v\),排序。

1.\(v_1>=L\)时,设\(f_{i,j,k}\)表示前i种用不多于j个限制能否达到k,用bitset维护。但好像状态数有\(4.5e8\)种,会炸裂,然而数据里根本就没有第一种情况啊...
2.设\(f_{i,j,k}\)表示前i种不多于j个最小的和%\(v_1=k\)对应的值。对于\(v_i>=L\)

\[f_{i,j,k}=min(f_{i-1,j,k},f_{i,j-1,k-v_i}+v_i) \]

对于\(v_i<L\)建出一个图,源点\(S\)向各个状态\(0\)~\(v_1-1\)\(f_{i-1,j,k}\)的边,\(k\)\(k+v_i\)\(v_i\)边,用最短路跑出的\(dis_{k}\)就是\(f_{i,j,k}\)
询问直接判断\(f_{n,C,question\mod v_i}\)是否小于\(question\)即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define int long long
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=55;
	int dis[10010],n,m,v[N],L,C,co,pos[10010],S,cnt,head[10010],q[10010],hd,tl;
	int f[52][32][10010];bool vis[10010];
	struct node{int next,to,w;}e[100100];
	inline void add(int next,int to,int w){e[++co].next=head[next],e[co].to=to,head[next]=co,e[co].w=w;}
	inline void spfa(int x){
		memset(dis,0x3f,sizeof(dis));
		q[hd=tl=1]=x;dis[x]=0;vis[x]=1;
		while(hd<=tl){
			int t=q[hd++];vis[t]=0;
			for(register int i=head[t];i;i=e[i].next){
				int j=e[i].to;
				if(dis[j]>dis[t]+e[i].w){
					dis[j]=dis[t]+e[i].w;
					if(!vis[j]){
						vis[j]=1;
						q[++tl]=j;
					}
				}
			}
		}
	}
	inline void solve(){
		memset(f,0x3f,sizeof(f));
		F(i,0,n)f[i][0][0]=0;
		F(i,1,n)F(j,1,C)
		if(v[i]>=L)F(k,0,v[1]-1)
			f[i][j][k]=min(f[i-1][j][k],f[i][j-1][((k-v[i])%v[1]+v[1])%v[1]]+v[i]);else f[i][j][k]=f[i-1][j][k];
		else{
			cnt=0;S=++cnt;
			F(k,0,v[1]-1)pos[k]=++cnt;memset(head,0,sizeof(head));co=0;
			F(k,0,v[1]-1)add(S,pos[k],f[i-1][j][k]),add(pos[k],pos[(k+v[i])%v[1]],v[i]);
			spfa(S);F(k,0,v[1]-1)f[i][j][k]=dis[pos[k]];
		}
		F(i,1,C)F(j,0,v[1]-1)f[n][i][j]=min(f[n][i][j],f[n][i-1][j]);
		F(i,1,m){
			int x=read();
			if(x>=f[n][C][x%v[1]])pf("Yes\n");
			else pf("No\n");
		}
	}
	inline short main(){
		//std::cout<<sizeof(f)/1024/1024;
		n=read(),m=read();F(i,1,n)v[i]=read();L=read(),C=read();
		std::sort(v+1,v+n+1);
		solve();
		return 0;
	}
}
signed main(){return EMT::main();}

毛衣琛

先用dfs组合拳水过了...待我去码个正解~

dfs Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n,val[25];
namespace emt{
	#define int long long
	inline int read()
	{
		int x=0,f=1;char ch=getchar();
		while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
		return x*f;
	}
	inline int min(int x,int y){return x<y?x:y;}
	inline int max(int x,int y){return x<y?y:x;}
	inline int abs(int x){return x<0?-x:x;}
	inline void swap(int &x,int &y){x^=y^=x^=y;}
	int sum=0,top1,top2,ans=0,stb[1<<20],cf[1<<20];
	int nv[1<<20][21];
	int dp[1<<20],size[1<<20];
	int vis[1<<20];
	struct node{
		int val,id;
	}f[1<<20],sta[1<<20];
	bool cmp(node a,node b)
	{
		if(a.val!=b.val) return a.val<b.val;
		return a.id<b.id;
	}
	signed main()
	{
		cf[0]=1;
		 for(int i=1;i<=n;i++)
		{sum+=val[i];}
		for(register int i=0;i<1<<n;i++)
		{
			for(register int j=1;j<=n;j++)
			{
				f[i].id=i;
				if(i&(1<<(j-1))) f[i].val+=val[j];
				if(f[i].val>sum/2) {f[i].val=123456789987654321;break;}
			}
		}
		sort(f+1,f+(1<<n),cmp);int m;
		for(int i=1;i<1<<n;i++)
		{
			if(f[i].val!=123456789987654321){m=i;}
			else break;
		}
		m++;
		for(int i=1;i<=m;i++) stb[i]=f[i].val;
		sort(stb+1,stb+1+m);
		int temp1=0,temp2=0;
		for(int i=1;i<m;i++)
		{
			if(f[temp1].val!=f[i].val)
			{
				temp1=lower_bound(stb+1,stb+1+m,f[i].val)-stb;
				temp2=lower_bound(stb+1,stb+1+m,f[i].val+1)-stb;
			}
			for(int j=i+1;j<temp2;j++)
			{
				if(f[i].id&f[j].id) continue;
				vis[f[i].id|f[j].id]=1;
			}
		}
		for(int i=1;i<1<<n;i++)
		if(vis[i]) ans++;
		cout<<ans;
		return 0;
	}
	#undef int
}
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	int ans,a[25],s[25],top,tot,q[1500000],hd,tl;const int mod=19260817;
	struct hash_table{
		int head[mod],co;
		struct node{
			int key,next;
		}e[1500000];
		inline int f(int x){
			return x%mod;
		}
		inline void add(int key){
			e[++co]=(node){key,head[f(key)]};
			head[f(key)]=co;
		}
		inline bool find(int x){
			for(register int i=head[f(x)];i;i=e[i].next)
				if(e[i].key==x)return 1;
			return 0;
		}
		inline void clear(){
			F(i,1,co)head[f(e[i].key)]=0;
			co=0;
		}
	}hs;
	bool check(int x){
		x-=s[top];
		if(!x)return 1;
		if(x<s[1])return 0;
		hs.clear();
		hs.add(0);
		F(i,1,top-1){
			hd=1,tl=0;
			F(j,1,hs.co)if(hs.e[j].key+s[i]<=x&&!hs.find(hs.e[j].key+s[i])){q[++tl]=hs.e[j].key+s[i];if(hs.e[j].key+s[i]==x)return 1;}
			while(hd<=tl)hs.add(q[hd++]);
		}return 0;
	}
	void dfs(int k){
		if(k==n+1){
			if(top<=1)return;
			if(tot&1)return;
			if(check(tot/2))++ans;
			return;
		}
		s[++top]=a[k];tot+=a[k];dfs(k+1);
		top--;tot-=a[k];dfs(k+1);
	}
	inline short main(){
		n=read();F(i,1,n)a[i]=read();
		std::sort(a+1,a+n+1);
		if(a[n]>=40000000){F(i,1,n)val[i]=a[i];return emt::main();}
		dfs(1);pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

upd in 2021-08-04 17:58:20 星期三
正解写出来了~以中间为分界线暴力插入查询能到达的状态和数即可。

Code
//彳 亍
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int M=2e6+7;
	int ans,n,a[25],mid,tot;const int mod=19260817;bool v[M];
	std::vector<int>w[M];
	struct hash_table{
		int head[mod],co;
		struct node{
			int key,next,val;
		}e[15000000];
		inline int f(int x){
			return (x+mod*2)%mod;
		}
		inline void add(int key,int val){
			e[++co]=(node){key,head[f(key)],val};
			head[f(key)]=co;
		}
		inline int find(int x){
			for(register int i=head[f(x)];i;i=e[i].next)
				if(e[i].key==x)return e[i].val;
			return -1;
		}
	}hs;
	inline void dfs1(int p,int l,int r,int zt){
		if(p==mid+1){
			int x=hs.find(l-r);
			if(x==-1)hs.add(l-r,++tot),x=tot;
			//pi(p);pi(l);pi(r);pn();
			w[x].push_back(zt);
			return;
		}
		dfs1(p+1,l,r,zt);
		dfs1(p+1,l+a[p],r,zt|(1<<(p-1)));
		dfs1(p+1,l,r+a[p],zt|(1<<(p-1)));
	}
	inline void dfs2(int p,int l,int r,int zt){
		if(p==n+1){
			int x=hs.find(r-l);
			if(x==-1)return;
			F(i,0,(int)w[x].size()-1){
				if(zt&w[x][i])continue;
				if(!(zt|w[x][i]))continue;
				if(!v[zt|w[x][i]])v[zt|w[x][i]]=1,ans++;
			}return;
		}
		dfs2(p+1,l+a[p],r,zt|(1<<(p-1)));
		dfs2(p+1,l,r+a[p],zt|(1<<(p-1)));
		dfs2(p+1,l,r,zt);
	}
	inline short main(){
		n=read();mid=n/2;
		F(i,1,n)a[i]=read();
		dfs1(1,0,0,0);
		dfs2(mid+1,0,0,0);
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

猫儿琛

\(f_{i,j}\)表示到\(i\)个数其排名为\(j\)的方案数,
\(pos_i\)表示\(i\)\(p\)序列中的位置。
\(pos_i<i\) 时要把\(i\)位置往左,先挪\(i-1\)再挪\(i\),相等无解,否则往右挪,先挪\(i\)再挪\(i-1\)打上挪动方式标记互相转化,用前缀和实现连续区间求和,最终答案就是\(sum_{n-1,n-1}\)

Code
//彳亍
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=5010,mod=1e9+7;
	int n,f[N][N],a[N],pos[N],sum[N][N];bool owo[N];
	inline short main(){
		n=read();
		F(i,1,n)a[i]=read()+1,pos[a[i]]=i;
		F(i,1,n){
			if(pos[i]==i){pi(0);exit(0);}
			if(pos[i]<i){
				owo[i]=1;
				D(j,i-1,1+pos[i])owo[j]=0;
			}else{
				owo[i]=0;
				F(j,i+1,pos[i]-1)owo[j]=1;
			}
		}
		f[1][1]=sum[1][1]=1;
		F(i,2,n-1){
			if(owo[i])
				F(j,1,i)f[i][j]=sum[i-1][j-1];
			else
				F(j,1,i)f[i][j]=(sum[i-1][i-1]-sum[i-1][j-1]+mod)%mod;
			F(j,1,i)sum[i][j]=(sum[i][j-1]+f[i][j])%mod;
		}
		pi(sum[n-1][n-1]);
		return 0;
	}
}
signed main(){return EMT::main();}

茂散琛

玄学看脸rand爆check,如果现在\(ran\)到的数不能满足现在最优答案就直接跳,利用\(clock\)函数实现程序结束。

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<ctime>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	bool v[10100];int s[10100],top,mod,k,n,ans,all,a[10100],b[10100];
	inline int random(int x){
		return 1ll*rand()*rand()%x;
	}
	inline bool check(int x){
		int cnt=1,tot=0;
		F(i,1,n){
			if(b[i]>x)return 0;
			if(tot+b[i]>x){tot=0;cnt++;}
			if(cnt>k)return 0;
			tot+=b[i];
		}
		if(cnt>k)return 0;return 1;
	}
	inline short main(){
		srand(time(0));int maxn=0;
		n=read(),mod=read(),k=read();F(i,1,n)a[i]=read(),ans+=a[i];
		while(1){
			if(clock()>=0.41*CLOCKS_PER_SEC||all==mod)break;
			int x=random(mod);
			if(v[x])continue;
			v[x]=1;all++;
			F(i,1,n)b[i]=(a[i]+x)%mod;
			if(check(ans)){
				int l=maxn,r=ans;
				while(l<=r){
					int mid=(l+r)>>1;
					if(check(mid))r=mid-1,ans=mid;
					else l=mid+1;
				}
			}else continue;
		}
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

2021-08-06 08:26:35 星期五

Game

权值线段树上维护未配对的\(a\),\(b\)数组和总共配对的对数,
然后在线段树上二分,看最大到哪里能对每一个\(b\)产生影响,然后把两个东西都删了,
分有配对,无配对讨论即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<set>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100;
	int n,b[N],a[N],c[N],maxn,ans,lans,key;std::set<int>s;
	struct seg{
		int sum[N<<2],a[N<<2],b[N<<2];
		inline void up(int p){
			sum[p]=min(a[p<<1|1],b[p<<1]);
			a[p]=a[p<<1]+a[p<<1|1]-sum[p];
			b[p]=b[p<<1]+b[p<<1|1]-sum[p];
			sum[p]+=sum[p<<1]+sum[p<<1|1];
		}
		void change(int p,int l,int r,int x,int va,int vb){
			if(l==r){
				if(va)a[p]+=va;else b[p]+=vb;
				return;
			}int mid=(l+r)>>1;
			if(x<=mid)change(p<<1,l,mid,x,va,vb);
			else change(p<<1|1,mid+1,r,x,va,vb);
			up(p);
		}
	}segm;
	inline bool check(int x){
		segm.change(1,1,maxn,x,-1,0);bool fl;
		if(segm.sum[1]+1==lans)fl=1;else fl=0;
		segm.change(1,1,maxn,x,1,0);return fl;
	}
	inline bool Check(int x){
		segm.change(1,1,maxn,x,-1,0);bool fl;
		if(segm.sum[1]==lans)fl=1;else fl=0;
		segm.change(1,1,maxn,x,1,0);return fl;
	}
	inline short main(){
		n=read();
		F(i,1,n)b[i]=read(),maxn=max(b[i],maxn);
		F(i,1,n)a[i]=read(),c[a[i]]++,maxn=max(maxn,a[i]);
		F(i,1,n)segm.change(1,1,maxn,b[i],0,1);
		F(i,1,n)segm.change(1,1,maxn,a[i],1,0),s.insert(a[i]);
		lans=segm.sum[1];
		F(i,1,n){
			segm.change(1,1,maxn,b[i],0,-1);
			int ans1,ans2;
			int l=b[i]+1,r=*s.rbegin(),ans=l-1;
			while(l<=r){
				int mid=(l+r)>>1;
				if(check(mid))l=mid+1,ans=mid;
				else r=mid-1;
			}ans1=ans;
			if(ans1!=b[i]){
				pi(ans1);
				segm.change(1,1,maxn,ans1,-1,0);
				lans--;c[ans1]--;if(!c[ans1])s.erase(ans1);
			}else{
				l=1,r=b[i],ans=l-1;
				while(l<=r){
					int mid=(l+r)>>1;
					if(Check(mid))l=mid+1,ans=mid;
					else r=mid-1;
				}ans2=ans;
				pi(ans2);
				segm.change(1,1,maxn,ans2,-1,0);
				c[ans2]--;
				if(!c[ans2])s.erase(ans2);
			}
		}
		return 0;
	}
}
signed main(){return EMT::main();}

Time

考虑贪心,当前最小的数一定会挪动到最左边或最右边,看这个数靠哪边近就往哪边挪,用树状数组维护向左需要挪动的距离。

Code
%: pragma GCC optimize("Ofast")
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100;
	int t[N],n,a[N],ans;
	inline void change(int x,int v){while(x<=n){t[x]+=v;x+=x&-x;}}
	inline int ask(int x){int ans=0;while(x){ans+=t[x];x-=x&-x;}return ans;}
	struct node{int l,r;std::vector<int>w;}e[N];
	inline short main(){
		n=read();
		F(i,1,n){
			int x=read();
			change(i,1);
			e[x].w.push_back(i),e[x].l=1,e[x].r=e[x].w.size()-1;
		}
		F(i,1,n){
			if(e[i].l){
				e[i].l--;
				while(e[i].l<=e[i].r){
					int x=e[i].w[e[i].l],y=e[i].w[e[i].r];
					int t=ask(x)-1,tt=ask(n)-ask(y);
					if(t<=tt){
						change(x,-1);
						ans+=t;e[i].l++;
					}else change(y,-1),ans+=tt,e[i].r--;
				}
			}
		}
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

Cover

本地RE交上去切了...真是玄学。
可以观察到每段区间形成树形关系,dfs1建边dfs2进行树形dp求得最优解,用set维护最优和保护空间。

Code


#include<vector>
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<set>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define int long long
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=3e5+100;int head[N],co,n,m,key;bool fl[N];
	struct node{int next,to;}e[N];std::multiset<int>f[N];
	inline void add(int next,int to){e[++co].next=head[next],e[co].to=to,head[next]=co;}
	struct awed{int l,r,val;friend bool operator <(awed a,awed b){return a.l==b.l?a.r>b.r:a.l<b.l;}}a[N];
	inline void dfs1(int k){
		fl[k]=1;
		while(a[key].l<=a[k].r&&key<=m)key++,add(k,key-1),dfs1(key-1);
	}
	inline void merge(std::multiset<int> &A,std::multiset<int> &B){
		if(A.size()<B.size())std::swap(A,B);
		std::vector<int>s;
		for(auto qwq:B)s.push_back(qwq+*A.begin()),A.erase(A.begin());
		for(auto qwq:s)A.insert(qwq);
	}
	inline void dfs2(int k){
		for(register int i=head[k];i;i=e[i].next){
			dfs2(e[i].to);
			merge(f[k],f[e[i].to]);
		}f[k].insert(-a[k].val);
	}
	inline short main(){
	//	file();
		n=read(),m=read();
		F(i,1,m)a[i].l=read(),a[i].r=read(),a[i].val=read();
		m++;a[m].l=1,a[m].r=n,a[m].val=0;
		std::sort(a+1,a+m+1);
		key=2;
		dfs1(1);
		dfs2(1);
		int ans=0;
		F(i,1,m-1){
			if(f[1].size()){
				ans-=*f[1].begin();
				f[1].erase(f[1].begin());
			}pi(ans);
		}
		return 0;
	}
}
signed main(){return EMT::main();}

2021-08-07 17:48:34 星期六

Smooth

开15个队列,每次从队顶最小的取出来把别的相同的都删掉,从第一个找到那个数的队列开始往后面塞去重。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define int long long
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%lld ",x);}inline void pn(){pf("\n");}
	int pri[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
	const int N=1e7+100;std::queue<int>q[20];
	int b,k,cnt=0,s[20],top;
	inline short main(){
		b=read(),k=read();
		F(i,1,b)q[i].push(1);
		while(1){
			int maxn=0x7ffffffffffffff;top=0;
			F(i,1,b)
				if(!q[i].empty()&&q[i].front()<maxn){
					maxn=q[i].front();top=0;
					s[++top]=i;
				}
				else if(!q[i].empty()&&q[i].front()==maxn)s[++top]=i;
			while(top)q[s[top--]].pop();
			cnt++;
			if(cnt==k){pi(maxn);return 0;}
			F(i,s[1],b)q[i].push(pri[i]*maxn);
		}
		return 0;
	}
}
signed main(){return EMT::main();}

Six

记忆化搜索,设\(f_{i,j}\)表示当前集合状态为\(i\),在不同数中出现的点对为\(j\)的方案数。
手写了个哈希表,j也用hash来表示,会快一点(可能

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	ll n;int sum[1<<10],prime[10],co,cnt[10],num[1<<10],ans;const int mod=1e9+7,Md=19260817;
	struct hash_table{
		int head[Md],co;
		struct node{
			int key1,key2,next,val;
		}e[1000000];
		inline int f(int key1,int key2){return (1ll*key1*131+key2)%Md;}
		inline void add(int key1,int key2,int val){
			e[++co]=(node){key1,key2,head[f(key1,key2)],val};
			head[f(key1,key2)]=co;
		}
		inline int find(int key1,int key2){
			for(register int i=head[f(key1,key2)];i;i=e[i].next)
				if(e[i].key1==key1&&e[i].key2==key2)return e[i].val;
			return -1;
		}
	}hs;
	inline bool check(int a,int b){
		F(i,1,n)F(j,1,i)if((a&(1<<(i-1)))&&(a&(1<<(j-1)))&&(b&(1<<((i-1)*5+j-1))))return 0;
		return 1;
	}
	inline int calc(int a,int b){
		int ans=0;
		F(i,1,n)F(j,1,i)if(((a&(1<<(i-1)))&&(b&(1<<(j-1))))||((a&(1<<(j-1)))&&b&(1<<(i-1))))ans|=(1<<((i-1)*5+j-1));
		return ans;
	}
	inline int dfs(int a,int b){
		int x=hs.find(a,b);
		if(x+1)return x;
		int ans=1;
		F(i,1,(1<<n)-1){
			if(!check(i,b))continue;
			ans=(1ll*ans+1ll*sum[i]*dfs(a|i,b|calc(a,i))%mod)%mod;
		}
		hs.add(a,b,ans);
		return ans;
	}
	inline short main(){
		n=read();
		F(i,2,sqrt(n)){
			if(i>n)break;
			if(n%i==0){
				co++;
				while(n%i==0){
					cnt[co]++;
					n/=i;
				}
			}
		}
		if(n>1)cnt[++co]=1;
		n=co;
		F(i,1,(1<<n)-1){
			sum[i]=1;
			F(j,1,n)if(i&(1<<(j-1)))sum[i]=1ll*sum[i]*cnt[j]%mod;
		}
		pi(dfs(0,0)-1);
		return 0;
	}
}
signed main(){return EMT::main();}

Walker

随机挑两个数来进行高斯消元,暴力代到其他数里验,挑到符合为止。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);/*freopen("my.out","w",stdout);*/}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100;
	struct node{db x1,x2,y1,y2;}A[N];int n;
	db a[5][10],ans[5],sc,co,si;
	inline int random(int x){
		return 1ll*rand()*rand()%x;
	}
	inline void gs(int n){
		F(i,1,n){
			db maxn=fabs(a[i][i]);int key=i;
			F(j,i+1,n)if(maxn<fabs(a[j][i]))key=j,maxn=fabs(a[j][i]);
			if(key!=i)std::swap(a[i],a[key]);
			F(j,i+1,n+1)a[i][j]/=a[i][i];a[i][i]=1;
			F(j,i+1,n)D(k,n+1,i)a[j][k]-=a[j][i]*a[i][k];
		}ans[n]=a[n][n+1];
		D(i,n-1,1){
			ans[i]=a[i][n+1];
			F(j,i+1,n)
				ans[i]-=ans[j]*a[i][j];
		}
	}
	inline bool check(db t1,db t2,db dx,db dy){
		int cnt=0;
		F(i,1,n){
			if(fabs(t1*A[i].x1-t2*A[i].y1+dx-A[i].x2)>1e-4)continue;
			if(fabs(t1*A[i].y1+t2*A[i].x1+dy-A[i].y2)>1e-4)continue;
			cnt++;
		}return cnt>=(n+1)/2;
	}
	inline short main(){
	//	file();
		srand(time(0));
		n=read();
		F(i,1,n)scanf("%lf%lf%lf%lf",&A[i].x1,&A[i].y1,&A[i].x2,&A[i].y2);
		while(1){
			int x=random(n)+1,y=random(n)+1;
			while(y==x)y=random(n+1);
			a[1][1]=A[x].x1;a[1][2]=-A[x].y1;a[1][3]=1;a[1][4]=0;a[1][5]=A[x].x2;
			a[2][1]=A[x].y1;a[2][2]=A[x].x1;a[2][3]=0;a[2][4]=1;a[2][5]=A[x].y2;
			a[3][1]=A[y].x1;a[3][2]=-A[y].y1;a[3][3]=1;a[3][4]=0;a[3][5]=A[y].x2;
			a[4][1]=A[y].y1;a[4][2]=A[y].x1;a[4][3]=0;a[4][4]=1;a[4][5]=A[y].y2;
			gs(4);
		//	pf("%.10lf %.10lf %.10lf %.10lf\n",ans[1],ans[2],ans[3],ans[4]);
			if(check(ans[1],ans[2],ans[3],ans[4]))break;
		}
		si=sqrt(ans[2]*ans[2]/(ans[2]*ans[2]+ans[1]*ans[1]));
		co=sqrt(1-si*si);
		if(ans[1]<0)co=-co;
		if(ans[2]<0)si=-si;
		db jiao=asin(si);if(co<0)jiao=3.1415926-jiao;jiao-=2*3.1415926;
		if(fabs(ans[1])>1e-6)sc=ans[1]/co;else sc=ans[2]/si;
		pf("%.10lf\n%.10lf\n%.10lf %.10lf",jiao,sc,ans[3],ans[4]);
		return 0;
	}
}
signed main(){return EMT::main();}

Hunter

一个猎人死在\(1\)号猎人前面的概率是\(\frac{w_i}{w_i+w_1}\),把所有的都加起来最后加一即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100,mod=998244353;
	int n,ans,w[N],tot;
	inline int ksm(int a,int b){
		int ans=1;
		while(b){
			if(b&1)ans=1ll*ans*a%mod;
			a=1ll*a*a%mod;
			b>>=1;
		}return ans;
	}
	inline short main(){
		n=read();
		w[1]=read();
		F(i,2,n){
			int x=read();
			(ans+=1ll*x*ksm(x+w[1],mod-2)%mod)%=mod;
		}
		pi(ans+1);
		return 0;
	}
}
signed main(){return EMT::main();}

Defence

线段树合并题。然而我已经忘记线段树合并是什么东西了

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}const int N=1e5+100;
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	int head[N],co,n,m,tot,q;
	struct node{int next,to;}e[N];int rt[N];
	inline void add(int next,int to){e[++co].next=head[next],e[co].to=to,head[next]=co;}
	struct tree{int ls,rs,lv,rv,mv;}t[N*40];
	#define ls(p) t[p].ls
	#define rs(p) t[p].rs
	#define lv(p) t[p].lv
	#define rv(p) t[p].rv
	#define mv(p) t[p].mv
	inline void up(int p,int l,int r){
		int mid=(r+l)>>1;
		if(!ls(p)){
			lv(p)=mv(p)=(mid-l+1)+lv(rs(p));
			rv(p)=rv(rs(p));
		}else if(!rs(p)){
			rv(p)=mv(p)=(r-mid)+rv(ls(p));
			lv(p)=lv(ls(p));
		}else{
			lv(p)=lv(ls(p));rv(p)=rv(rs(p));
			mv(p)=max(mv(ls(p)),max(mv(rs(p)),rv(ls(p))+lv(rs(p))));
		}
	}
	void insert(int &p,int l,int r,int x){
		if(!p)p=++tot;
		if(l==r){lv(p)=rv(p)=mv(p)=0;return;}
		int mid=(l+r)>>1;
		if(x<=mid)insert(ls(p),l,mid,x);
		else insert(rs(p),mid+1,r,x);
		up(p,l,r);
	}
	int ans[N];
	int merge(int a,int b,int l,int r){
		if(!a||!b)return a|b;
		if(l==r){lv(a)=rv(a)=mv(a)=0;return a;}
		int mid=(l+r)>>1;
		ls(a)=merge(ls(a),ls(b),l,mid);
		rs(a)=merge(rs(a),rs(b),mid+1,r);
		up(a,l,r);return a;
	}
	void dfs(int k){
		for(register int i=head[k];i;i=e[i].next)
			dfs(e[i].to),rt[k]=merge(rt[k],rt[e[i].to],1,m);
		if(!rt[k])ans[k]=-1;else ans[k]=max(lv(rt[k])+rv(rt[k]),mv(rt[k]));
	}
	inline short main(){
		n=read(),m=read(),q=read();
		F(i,1,n-1){
			int x=read(),y=read();
			add(x,y);
		}
		F(i,1,q){
			int x=read(),v=read();
			insert(rt[x],1,m,v);
		}dfs(1);
		F(i,1,n)pi(ans[i]),pn();
		return 0;
	}
}
signed main(){return EMT::main();}

Connect

\(dp_{i,j}\)表示当前状态为\(i\),链的最后一个是\(j\)的最大边权总和,
\(f_{i,j}\)表示\(i\)集合向\(j\)连边的权值,\(in_i\)表示\(i\)内部集合的边权,预处理出这两个数组然后枚举转移即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=50;
	int n,m,w[N][N],all,in[1<<15],f[1<<15][16],dp[1<<15][16];
	inline short main(){
		file();
		n=read(),m=read();all=(1<<n)-1;
		F(i,1,m){
			int x=read(),y=read();
			w[x][y]=w[y][x]=read();
		}
		F(i,1,(1<<n)-1)F(j,1,n)if(i&(1<<(j-1))){F(k,j+1,n)if(i&(1<<(k-1)))in[i]+=w[j][k];}else F(k,1,n)if(i&(1<<(k-1)))f[i][j]+=w[j][k];
		F(i,1,(1<<n)-1)if(i&1){
				F(j,1,n)if(i&(1<<(j-1))){
				F(k,1,n)if(w[j][k]&&!(i&(1<<(k-1))))dp[i|(1<<(k-1))][k]=max(dp[i|(1<<(k-1))][k],dp[i][j]+w[j][k]);
				for(int k=all^i;k;(--k)&=(all^i))if(!(i&k)&&f[k][j])dp[i|k][j]=max(dp[i|k][j],dp[i][j]+f[k][j]+in[k]);}
			}
		pi(in[all]-dp[all][n]);
		return 0;
	}
}
signed main(){return EMT::main();}

2021-08-09 11:25:29 星期一

Merchant

当time=0时若不能满足,则符合单调性,于是可以二分。
nth_element实现O(N)check,于是就出来了。

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define int long long
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=1e6+100;int cnt;ll val[N];
	struct node{int k,b;}a[N];int n,m;ll s;
	bool com(node a,node b){return a.b>b.b;}
	bool cmp(ll a,ll b){return a>b;}
	inline bool check(int t){
		F(i,1,n)val[i]=a[i].k*t+a[i].b;
		ll tot=0;
		std::nth_element(val+1,val+m+1,val+n+1,cmp);
		F(i,1,m){if(val[i]>0)tot+=val[i];if(tot>=s)return 1;}
		return 0; 
	}
	inline short main(){
		n=read(),m=read(),s=read();
		F(i,1,n)a[i].k=read(),a[i].b=read();
		if(check(0)){pi(0);return 0;}
		int l=1,r=(int)1e9,ans=0;
		while(l<=r){
			int mid=(l+r)>>1;
			if(check(mid))r=mid-1,ans=mid;
			else l=mid+1;
		}pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

Equation

一个结点k的x可以用\(\sum\limits_{i=k}^{i=fa[i]}w_i*(-1)^{deep[k]-deep[i]}+x_1*(-1)^{deep[k]-deep[1]}\)来表示
发现修改点的子树中深度和k同奇偶性的与k同加减,否则一加一减。
于是对奇偶分别建线段树,区间修改,单点查询。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e6+100;
	int deep[N],head[N],co,dfn[N],last[N],ti,n,q,w[N];
	struct node{int next,to;}e[N];
	inline void add(int next,int to){e[++co].next=head[next],e[co].to=to,head[next]=co;}
	inline int pan(int dep){return dep&1?-1:1;}
	struct seg{
		int val[N<<2],lz[N<<2];
		void insert(int p,int l,int r,int x,int v){
		//	pi(p);pi(l);pi(r);pi(x);pi(v);pn();
			if(l==r){val[p]=v;return;}
			int mid=(l+r)>>1;
			if(x<=mid)insert(p<<1,l,mid,x,v);
			else insert(p<<1|1,mid+1,r,x,v);
		}
		inline void down(int p){
			if(lz[p]){
				lz[p<<1]+=lz[p];
				lz[p<<1|1]+=lz[p];
				val[p<<1]+=lz[p];
				val[p<<1|1]+=lz[p];
				lz[p]=0;
			}
		}
		void change(int p,int l,int r,int ql,int qr,int v){
			if(l>=ql&&r<=qr){
				val[p]+=v;
				lz[p]+=v;
				return;
			}down(p);int mid=(l+r)>>1;
			if(qr<=mid)change(p<<1,l,mid,ql,qr,v);
			else if(ql>mid)change(p<<1|1,mid+1,r,ql,qr,v);
			else change(p<<1,l,mid,ql,mid,v),change(p<<1|1,mid+1,r,mid+1,qr,v);
		}
		int ask(int p,int l,int r,int x){
			if(l==r)return val[p];
			down(p);int mid=(l+r)>>1;
			if(x<=mid)return ask(p<<1,l,mid,x);
			else return ask(p<<1|1,mid+1,r,x);
		}
	}segm[2];
	void dfs(int k,int val){
		dfn[k]=++ti;segm[deep[k]&1].insert(1,1,n,dfn[k],val);
		for(register int i=head[k];i;i=e[i].next){
			int j=e[i].to;deep[j]=deep[k]+1;
			dfs(j,-val+w[j]);
		}last[k]=ti;
	}
	inline short main(){
		//file();
		n=read(),q=read();
		F(i,2,n){
			int fa=read();add(fa,i);
			w[i]=read();
		}dfs(1,0);
		F(i,1,q){
			int opt=read();
			if(opt==1){
				int u=read(),v=read();ll y=read();
				y-=segm[deep[u]&1].ask(1,1,n,dfn[u])+segm[deep[v]&1].ask(1,1,n,dfn[v]);
				int x=pan(deep[u])+pan(deep[v]);
				if(!x&&!y){
					pf("inf\n");
				}else if(!x||(y%x!=0)){
					pf("none\n");
				}else{
					pi(y/x);pn();
				}
			}else{
				int u=read(),v=read();
				ll vv=v-w[u];w[u]=v;
				segm[deep[u]&1].change(1,1,n,dfn[u],last[u],vv);
				segm[(deep[u]&1)^1].change(1,1,n,dfn[u],last[u],-vv);
			}
		}
		return 0;
	}
}
signed main(){return EMT::main();}

爆int了,淦。

Rectangle

考虑对每一列建一个树状数组,把左边的点信息依次统计到树状数组上,加上他们的贡献并去重用指针维护当前位置即可。

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=2.5e3+5,M=2500,E=1e4+10,mod=1e9+7;
	struct dp{int siz,sum;}t[N][N];int n;int a[N][N],ans;bool vis[N][N];
	inline dp ask(int a,int b){dp ans;ans.siz=ans.sum=0;while(b){ans.siz+=t[a][b].siz,ans.sum+=t[a][b].sum;b-=b&-b;}return ans;}
	inline void change(int a,int b,dp c){while(b<=M){t[a][b].siz+=c.siz,t[a][b].sum+=c.sum;b+=b&-b;}}
	inline short main(){
		n=read();
		F(i,1,n){
			int x=read(),y=read();
			a[x][++a[x][0]]=y;
		}
		F(i,1,M)std::sort(a[i]+1,a[i]+a[i][0]+1),a[i][a[i][0]+1]=2501;
		F(i,1,M){
			if(!a[i][0])continue;
			F(j,1,a[i][0])
				if(!vis[i][a[i][j]]){
					vis[i][a[i][j]]=1;
					change(i,a[i][j],(dp){1,a[i][j]});
				}
			D(j,i-1,1){
				if(!a[j][0])continue;
				int l1=1,l2=1;
				F(k,1,a[j][0])
					if(!vis[i][a[j][k]]){
						vis[i][a[j][k]]=1;
						change(i,a[j][k],(dp){1,a[j][k]});
					}
				int qwq=max(a[i][1],a[j][1]);
				while(a[i][l1+1]<=qwq)l1++;
				while(a[j][l2+1]<=qwq)l2++;
				while(l1<=a[i][0]&&l2<=a[j][0]){
					int fl=min(a[i][l1+1],a[j][l2+1]);
					dp A=ask(i,fl-1),B=ask(i,qwq-1),C=ask(i,min(a[i][l1],a[j][l2]));
					(ans+=1ll*(i-j)*(1ll*(A.sum-B.sum)*C.siz%mod-1ll*(A.siz-B.siz)*C.sum%mod+mod)%mod)%=mod;
					qwq=fl;
					if(a[i][l1+1]<=qwq)l1++;
					if(a[j][l2+1]<=qwq)l2++;
				}
			}
		}pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

玩游戏

将前缀和求出来,看能不能把l或r走到前缀和比现在小的位置,都不能就无解,走到最小后反着走一遍,流程一致

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define int long long
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline ll max(ll a,ll b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100;const ll inf=1e18;
	ll a[N];int n,k;
	inline bool check(int l,int r){
		int key1=0,key2=0;ll max1=-inf,max2=-inf,sum1=0,sum2=0,sum=0;
		D(i,l-1,0){
			sum1+=a[i];
			max1=max(max1,sum1);
			if(sum1<=0){key1=i;break;}
		}
		F(i,r+1,n+1){
			sum2+=a[i];
			max2=max(max2,sum2);
			if(sum2<=0){key2=i;break;}
		}
		while(1){
			if(l==1&&r==n)return 1;
			if(sum+max1<=0&&key1){
				sum+=sum1;l=key1;sum1=0;max1=-inf;
				D(i,l-1,0){
					sum1+=a[i];
					max1=max(max1,sum1);
					if(sum1<=0){key1=i;break;}
				}
			}else if(sum+max2<=0&&key2<=n){
				sum+=sum2;r=key2;sum2=0;max2=-inf;
				F(i,r+1,n+1){
					sum2+=a[i];
					max2=max(max2,sum2);
					if(sum2<=0){key2=i;break;}
				}
			}else break;
		}if(l>r)return 0;
		int l1=0,r1=n+1;sum=0;
		F(i,1,n)sum+=a[i],a[i]*=-1;
		if(sum>0)return 0;
		sum1=sum2=0;max1=max2=-inf;a[l]=a[r]=-inf;
		F(i,1+l1,l){
			sum1+=a[i];max1=max(max1,sum1);
			if(sum1<=0){key1=i;break;}
		}
		D(i,r1-1,r){
			sum2+=a[i];max2=max(max2,sum2);
			if(sum2<=0){key2=i;break;}
		}
		while(1){
			if(l1==l-1&&r1==r+1)return 1;
			if(sum+max1<=0&&key1!=l){
				sum+=sum1;sum1=0;l1=key1;max1=-inf;
				F(i,l1+1,l){
					sum1+=a[i];max1=max(max1,sum1);
					if(sum1<=0){key1=i;break;}
				}
			}else if(sum+max2<=0&&key2!=r){
				sum+=sum2;sum2=0;r1=key2;max2=-inf;
				D(i,r1-1,r){
					sum2+=a[i];max2=max(max2,sum2);
					if(sum2<=0){key2=i;break;}
				}
			}else return 0;
		}
	}
	inline short main(){
		int T=read();
		while(T--){
			n=read(),k=read();
			read();--n;F(i,1,n)a[i]=read();
			a[0]=a[n+1]=-inf;--k;
			puts(check(k+1,k)?"Yes":"No");
		}
		return 0;
	}
}
signed main(){return EMT::main();}

最短路

建出反边,rhead记录现在最优情况下的边,用spfa跑出来。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<bitset>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=255,inf=1e9;
	struct pt{int a,b;};
	std::queue<pt>q;
	int dis[N][N],w[N],n,m;bool vis[N][N];
	std::bitset<N>hv[N][N];
	struct node{
		int head[N],co;
		struct nodee{int next,to;}e[N*N];
		inline void add(int next,int to){e[++co].next=head[next],e[co].to=to,head[next]=co;}
	}e[2];
	inline void spfa(){
		F(i,1,n)F(j,1,n)dis[i][j]=inf;
		hv[1][1][1]=1;q.push((pt){1,1});dis[1][1]=w[1];
		while(!q.empty()){
			pt x=q.front();q.pop();
			int xa=x.a,xb=x.b;
			vis[xa][xb]=0;
			for(register int i=e[0].head[xa];i;i=e[0].e[i].next){
				int j=e[0].e[i].to;
				if(hv[xa][xb][j]&&dis[j][xb]>dis[xa][xb]){
					dis[j][xb]=dis[xa][xb];
					hv[j][xb]=hv[xa][xb];//,sizeof(hv[xa][xb]));
					if(!vis[j][xb]){
						q.push((pt){j,xb});
						vis[j][xb]=1;
					}
				}else if(!hv[xa][xb][j]&&dis[j][xb]>dis[xa][xb]+w[j]){
					dis[j][xb]=dis[xa][xb]+w[j];
					hv[j][xb]=hv[xa][xb];//,sizeof(hv[xa][xb]));
					hv[j][xb][j]=1;
					if(!vis[j][xb]){
						q.push((pt){j,xb});
						vis[j][xb]=1;
					}
				}
			}
			for(register int i=e[1].head[xb];i;i=e[1].e[i].next){
				int j=e[1].e[i].to;
				if(hv[xa][xb][j]&&dis[xa][j]>dis[xa][xb]){
					dis[xa][j]=dis[xa][xb];
					hv[xa][j]=hv[xa][xb];//,sizeof(hv[xa][xb]));
					if(!vis[xa][j]){
						q.push((pt){xa,j});
						vis[xa][j]=1;
					}
				}else if(!hv[xa][xb][j]&&dis[xa][j]>dis[xa][xb]+w[j]){
					dis[xa][j]=dis[xa][xb]+w[j];
					hv[xa][j]=hv[xa][xb];
					hv[xa][j][j]=1;
					if(!vis[xa][j]){
						q.push((pt){xa,j});
						vis[xa][j]=1;
					}
				}
			}
		}
		pi(dis[n][n]==inf?-1:dis[n][n]);
	}
	inline short main(){
		//file();
		n=read(),m=read();
		F(i,1,n)w[i]=read();
		F(i,1,m){
			int x=read(),y=read();
			e[0].add(x,y);e[1].add(y,x);
		}spfa();
		return 0;
	}
}
signed main(){return EMT::main();}

Dove 打扑克

当前含有的种类数是\(\sqrt n\)级别的。所以存到set里面,用并查集维护所在牌堆,线段树区间求和。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<set>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100;
	int fa[N],siz[N],cnt;std::set<int>s;
	inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
	struct seg{
		int sum[N<<2];
		inline int ask(int p,int l,int r,int ql,int qr){
			if(l>=ql&&r<=qr)return sum[p];
			int mid=(l+r)>>1;
			if(qr<=mid)return ask(p<<1,l,mid,ql,qr);
			if(ql>mid)return ask(p<<1|1,mid+1,r,ql,qr);
			return ask(p<<1,l,mid,ql,mid)+ask(p<<1|1,mid+1,r,mid+1,qr);
		}
		inline void change(int p,int l,int r,int x,int v){
			if(l==r){
				sum[p]+=v;
				return;
			}int mid=(l+r)>>1;
			if(x<=mid)change(p<<1,l,mid,x,v);
			else change(p<<1|1,mid+1,r,x,v);
			sum[p]=sum[p<<1]+sum[p<<1|1];
		}
	}segm;int n,m,tong[N];
	inline short main(){
		//file();
		n=read();m=read();
		F(i,1,n)fa[i]=i,siz[i]=1;
		tong[1]=cnt=n;s.insert(1);
		segm.change(1,1,n,1,n);
		F(i,1,m){
			int opt=read();
			if(opt==1){
				int x=read(),y=read();
				int fx=find(x),fy=find(y);
				if(fx==fy)continue;
				fa[fy]=fx;
				tong[siz[fx]]--;segm.change(1,1,n,siz[fx],-1);
				if(!tong[siz[fx]])s.erase(siz[fx]);
				tong[siz[fy]]--;segm.change(1,1,n,siz[fy],-1);
				if(!tong[siz[fy]])s.erase(siz[fy]);siz[fx]+=siz[fy];siz[fy]=0;
				tong[siz[fx]]++;segm.change(1,1,n,siz[fx],1);
				if(tong[siz[fx]]==1)s.insert(siz[fx]);
				cnt--;
			}else{
				int c=read(),y=*(--s.end());ll ans=0;
				if(!c){
					pi(1ll*cnt*(cnt-1)/2);pn();
					continue;
				}
				for(auto it=s.begin();it!=s.end();it++){
					int x=*it;//pi(x);pn();
					if(x+c>y)break;
					//pi(segm.ask(1,1,n,x+c,n));pn();
					ans+=1ll*segm.ask(1,1,n,x+c,n)*tong[x];
				}pi(ans);pn();
			}
		}
		return 0;
	}
}
signed main(){return EMT::main();}

Cicada 与排序

预处理出逆元和组合数,离散化,用结构体存储当前点到某位置的概率,最后概率*位置就是期望。用归并排序得到概率,分 数在中线左边和右边讨论,如果只在一边会在下个递归讨论。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int mod=998244353,N=505;
	inline int ksm(int a,int b){
		int ans=1;
		while(b){
			if(b&1)ans=1ll*a*ans%mod;
			a=1ll*a*a%mod;
			b>>=1;
		}return ans;
	}int n,jc[N],inv[N],inv2[N],a[N],s[N];
	inline void init(){
		jc[0]=inv[0]=inv[1]=inv2[0]=1;
		F(i,1,500)jc[i]=1ll*jc[i-1]*i%mod;
		inv[500]=ksm(jc[500],mod-2);
		D(i,499,2)inv[i]=1ll*inv[i+1]*(i+1)%mod;
		inv2[500]=ksm(ksm(2,500),mod-2);
		D(i,499,1)inv2[i]=inv2[i+1]*2%mod;
	}
	inline int C(int m,int n){
		if(n<m)return 0;if(n==m||!m)return 1;
		return 1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;
	}
	struct dp{int a,id,pt[N];}p[N],p2[N];
	inline void lsh(){
		std::sort(s+1,s+n+1);
		int len=std::unique(s+1,s+n+1)-s-1;
		F(i,1,n)p[i].a=std::lower_bound(s+1,s+len+1,p[i].a)-s;
	}
	inline void merge_sort(int l,int r){
		if(l==r)return;
		int mid=(l+r)>>1,len=r-l+1;
		merge_sort(l,mid);
		merge_sort(mid+1,r);
		int jud[N],num[N][2];memset(num,0,sizeof(num));
		F(i,l,mid){num[p[i].a][0]++;jud[p[i].id]=1;}
		F(i,mid+1,r){num[p[i].a][1]++;jud[p[i].id]=2;}
		memcpy(p2+l,p+l,sizeof(dp)*len);
		F(i,l,r)F(j,1,n)p[i].pt[j]=0;
		F(i,l,r)
			if(num[p[i].a][0]&&num[p[i].a][1]){
				int val=p[i].a;
				if(jud[i]==1){
					F(j,1,num[val][0]){
						F(k,1,num[val][1]+j-1)
							(p[i].pt[k]+=1ll*p2[i].pt[j]*C(j-1,k-1)%mod*inv2[k]%mod)%=mod;
						F(k,num[val][1],num[val][1]+j-1)
							(p[i].pt[j+num[val][1]]+=1ll*p2[i].pt[j]*C(num[val][1]-1,k-1)%mod*inv2[k]%mod)%=mod;
					}
				}else{
					F(j,1,num[val][1]){
						F(k,1,num[val][0]+j-1)
							(p[i].pt[k]+=1ll*p2[i].pt[j]*C(j-1,k-1)%mod*inv2[k]%mod)%=mod;
						F(k,num[val][0],num[val][0]+j-1)
							(p[i].pt[j+num[val][0]]+=1ll*p2[i].pt[j]*C(num[val][0]-1,k-1)%mod*inv2[k]%mod)%=mod;
					}
				}
			}
		F(i,1,r)F(j,1,n)if(!p[i].pt[j])p[i].pt[j]=p2[i].pt[j];
	}int ans[N],tong[N],pre[N];
	inline short main(){
		n=read();F(i,1,n){s[i]=p[p[i].id=i].a=read();F(j,1,n)p[i].pt[j]=1;}
		init();lsh();merge_sort(1,n);
		F(i,1,n)tong[p[i].a]++;
		F(i,1,n)pre[i]=pre[i-1]+tong[i];
		F(i,1,n){
			F(j,1,tong[p[i].a]){
				(ans[i]+=1ll*(pre[p[i].a-1]+j)%mod*p[i].pt[j]%mod)%=mod;
			}pi(ans[i]);
		}
		return 0;
	}
}
signed main(){return EMT::main();}

Cicada 拿衣服

打正解是不可能打正解的,这辈子都不可能打正解的,就只能乱搞搞,维持一下生活这样子啊
考场乱搞骗得72,实际上数组开小了,应该是80...
当数据范围大时,如果数据不是精心构造的,最长长度不会很长,考场上也是这么想的,于是枚举到l+100就可以停了(我赌你的数据里,没有答案

Code


#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e6+100;
	struct dp{int maxval,minval,_6,_7;};
	struct seg{
		dp t[N<<2];int val[N<<2],lz[N<<2];
		#define maxv(p) t[p].maxval
		#define minv(p) t[p].minval
		#define _6(p) t[p]._6
		#define _7(p) t[p]._7
		inline void up(int p){
			maxv(p)=max(maxv(p<<1),maxv(p<<1|1));
			minv(p)=min(minv(p<<1),minv(p<<1|1));
			_6(p)=_6(p<<1)|_6(p<<1|1);
			_7(p)=_7(p<<1)&_7(p<<1|1);
		}
		inline void ins(int p,int l,int r,int x,int v){
			if(l==r){maxv(p)=minv(p)=_6(p)=_7(p)=v;return;}
			int mid=(l+r)>>1;if(x<=mid)ins(p<<1,l,mid,x,v);else ins(p<<1|1,mid+1,r,x,v);
			up(p);
		}
		inline dp ask(int p,int l,int r,int ql,int qr){
			if(l>=ql&&r<=qr)return t[p];
			int mid=(l+r)>>1;if(qr<=mid)return ask(p<<1,l,mid,ql,qr);
			if(ql>mid)return ask(p<<1|1,mid+1,r,ql,qr);
			dp a=ask(p<<1,l,mid,ql,mid),b=ask(p<<1|1,mid+1,r,mid+1,qr);
			return (dp){max(a.maxval,b.maxval),min(a.minval,b.minval),a._6|b._6,a._7&b._7};
		}
		inline void down(int p){
			if(lz[p]){
				lz[p<<1]=max(lz[p],lz[p<<1]);
				lz[p<<1|1]=max(lz[p],lz[p<<1|1]);
				val[p<<1]=max(val[p<<1],lz[p]);
				val[p<<1|1]=max(val[p<<1|1],lz[p]);
				lz[p]=0;
			}
		}
		inline void change(int p,int l,int r,int ql,int qr,int v){
			if(l>=ql&&r<=qr){
				val[p]=max(val[p],v);
				lz[p]=max(val[p],v);
				return;
			}int mid=(l+r)>>1;
			if(qr<=mid)change(p<<1,l,mid,ql,qr,v);
			else if(ql>mid)change(p<<1|1,mid+1,r,ql,qr,v);
			else change(p<<1,l,mid,ql,mid,v),change(p<<1|1,mid+1,r,mid+1,qr,v);
		}
		inline int getans(int p,int l,int r,int x){
			if(l==r)return val[p];
			int mid=(l+r)>>1;down(p);
			if(x<=mid)return getans(p<<1,l,mid,x);
			else return getans(p<<1|1,mid+1,r,x);
		}
	}segm;
	int n,k,a[N];
	inline short main(){
		//file();
		n=read(),k=read();
		F(i,1,n)a[i]=read();
		F(l,1,n){
			int maxval=a[l],minval=a[l],_6=a[l],_7=a[l];int maxn=-1;
			F(r,l+1,n){
				
				minval=min(minval,a[r]);
				_6|=a[r];_7&=a[r];
				maxval=max(maxval,a[r]);
				if(minval+_6-maxval-_7>=k)
					maxn=r;
				else if(n>30000&&r-l+1>100) break;
			}if(maxn!=-1)segm.change(1,1,n,l,maxn,maxn-l+1);
		}
		F(i,1,n){int x=segm.getans(1,1,n,i);pi(x==0?-1:x);}
		return 0;
	}
}
signed main(){return EMT::main();}

数列

exgcd求解特解,分\(x,y\)是最小正数、最大负数四种讨论即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline ll max(ll a,ll b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100;
	struct que{int a,b,w;friend bool operator <(que a,que b){return min(a.a,a.b)<min(b.a,b.b);}}q[N];
	int n,s[N<<1],cnt;
	struct seg{
		ll val[N<<3],lz[N<<3];
		inline void down(int p){
			if(lz[p]){
				val[p<<1]+=lz[p];
				val[p<<1|1]+=lz[p];
				lz[p<<1]+=lz[p];
				lz[p<<1|1]+=lz[p];
				lz[p]=0;
			}
		}
		inline void add(int p,int l,int r,int ql,int qr,int v){
			if(l>=ql&&r<=qr){
				val[p]+=v;
				lz[p]+=v;
				return;
			}down(p);int mid=(l+r)>>1;
			if(qr<=mid)add(p<<1,l,mid,ql,qr,v);
			else if(ql>mid)add(p<<1|1,mid+1,r,ql,qr,v);
			else add(p<<1,l,mid,ql,mid,v),add(p<<1|1,mid+1,r,mid+1,qr,v);
			val[p]=max(val[p<<1],val[p<<1|1]);
		}
		inline ll ask(int p,int l,int r,int ql,int qr){
			if(l>=ql&&r<=qr)return val[p];
			int mid=(l+r)>>1;down(p);
			if(qr<=mid)return ask(p<<1,l,mid,ql,qr);
			if(ql>mid)return ask(p<<1|1,mid+1,r,ql,qr);
			return max(ask(p<<1,l,mid,ql,mid),ask(p<<1|1,mid+1,r,mid+1,qr));
		}
		inline void change(int p,int l,int r,int x,ll v){
			if(l==r){val[p]=max(val[p],v);return;}
			int mid=(l+r)>>1;down(p);
			if(x<=mid)change(p<<1,l,mid,x,v);else change(p<<1|1,mid+1,r,x,v);
			val[p]=max(val[p<<1],val[p<<1|1]);
		}
	}segm;
	inline short main(){
		//file();
		n=read();
		F(i,1,n)q[i].a=read(),q[i].b=read(),s[++cnt]=q[i].a,s[++cnt]=q[i].b,q[i].w=read();
		std::sort(s+1,s+cnt+1);int len=std::unique(s+1,s+cnt+1)-s-1;
		std::sort(q+1,q+n+1);
		F(i,1,n)q[i].a=std::lower_bound(s+1,s+len+1,q[i].a)-s,q[i].b=std::lower_bound(s+1,s+len+1,q[i].b)-s;
		F(i,1,n){
			if(q[i].a<q[i].b)segm.add(1,1,len,q[i].a+1,q[i].b,q[i].w);
			segm.change(1,1,len,q[i].a,(ll)q[i].w+segm.ask(1,1,len,1,min(q[i].a,q[i].b)));
		}pi(segm.ask(1,1,len,1,len));
		return 0;
	}
}
signed main(){return EMT::main();}

数对

加了排序的队长快跑,别的完全一致,不复读了。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline ll max(ll a,ll b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100;
	struct que{int a,b,w;friend bool operator <(que a,que b){return min(a.a,a.b)<min(b.a,b.b);}}q[N];
	int n,s[N<<1],cnt;
	struct seg{
		ll val[N<<3],lz[N<<3];
		inline void down(int p){
			if(lz[p]){
				val[p<<1]+=lz[p];
				val[p<<1|1]+=lz[p];
				lz[p<<1]+=lz[p];
				lz[p<<1|1]+=lz[p];
				lz[p]=0;
			}
		}
		inline void add(int p,int l,int r,int ql,int qr,int v){
			if(l>=ql&&r<=qr){
				val[p]+=v;
				lz[p]+=v;
				return;
			}down(p);int mid=(l+r)>>1;
			if(qr<=mid)add(p<<1,l,mid,ql,qr,v);
			else if(ql>mid)add(p<<1|1,mid+1,r,ql,qr,v);
			else add(p<<1,l,mid,ql,mid,v),add(p<<1|1,mid+1,r,mid+1,qr,v);
			val[p]=max(val[p<<1],val[p<<1|1]);
		}
		inline ll ask(int p,int l,int r,int ql,int qr){
			if(l>=ql&&r<=qr)return val[p];
			int mid=(l+r)>>1;down(p);
			if(qr<=mid)return ask(p<<1,l,mid,ql,qr);
			if(ql>mid)return ask(p<<1|1,mid+1,r,ql,qr);
			return max(ask(p<<1,l,mid,ql,mid),ask(p<<1|1,mid+1,r,mid+1,qr));
		}
		inline void change(int p,int l,int r,int x,ll v){
			if(l==r){val[p]=max(val[p],v);return;}
			int mid=(l+r)>>1;down(p);
			if(x<=mid)change(p<<1,l,mid,x,v);else change(p<<1|1,mid+1,r,x,v);
			val[p]=max(val[p<<1],val[p<<1|1]);
		}
	}segm;
	inline short main(){
		//file();
		n=read();
		F(i,1,n)q[i].a=read(),q[i].b=read(),s[++cnt]=q[i].a,s[++cnt]=q[i].b,q[i].w=read();
		std::sort(s+1,s+cnt+1);int len=std::unique(s+1,s+cnt+1)-s-1;
		std::sort(q+1,q+n+1);
		F(i,1,n)q[i].a=std::lower_bound(s+1,s+len+1,q[i].a)-s,q[i].b=std::lower_bound(s+1,s+len+1,q[i].b)-s;
		F(i,1,n){
			if(q[i].a<q[i].b)segm.add(1,1,len,q[i].a+1,q[i].b,q[i].w);
			segm.change(1,1,len,q[i].a,(ll)q[i].w+segm.ask(1,1,len,1,min(q[i].a,q[i].b)));
		}pi(segm.ask(1,1,len,1,len));
		return 0;
	}
}
signed main(){return EMT::main();}

最小距离

记录\(pre_i\)表示当前\(dis_i\)是由哪个点转移过来的,跑dij最短路同时更新pre,最后枚举每条边如果pre不同更新pre答案即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define int long long
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=2e5+100;
	int head[N],co,n,m,p,x[N],dis[N],pre[N];bool vis[N];
	struct node{int from,next,to,w;}e[N<<1];
	struct dp{int x,w;friend bool operator <(dp a,dp b){return a.w>b.w;}};
	inline void add(int next,int to,int w){e[++co].next=head[next],e[co].to=to,e[co].w=w,head[next]=co;e[co].from=next;}
	inline void djkl(){
		memset(dis,0x3f,sizeof(dis));
		std::priority_queue<dp>q;
		F(i,1,p)q.push((dp){x[i],0}),dis[x[i]]=0,pre[x[i]]=x[i];
		while(!q.empty()){
			int x=q.top().x;q.pop();
			if(vis[x])continue;
			vis[x]=1;
			for(register int i=head[x];i;i=e[i].next){
				int j=e[i].to;
				if(dis[j]>dis[x]+e[i].w){
					dis[j]=dis[x]+e[i].w;
					pre[j]=pre[x];
					q.push((dp){j,dis[j]});
				}
			}
		}
	}int ans[N];
	inline short main(){
		memset(ans,0x3f,sizeof(ans));
		n=read(),m=read(),p=read();
		F(i,1,p)x[i]=read();
		F(i,1,m){
			int x=read(),y=read(),z=read();
			add(x,y,z);add(y,x,z);
		}djkl();
		for(register int i=1;i<=co;i+=2){
			if(pre[e[i].from]!=pre[e[i+1].from]){
				ans[pre[e[i].from]]=min(ans[pre[e[i].from]],dis[e[i].to]+dis[e[i].from]+e[i].w);
				ans[pre[e[i].to]]=min(ans[pre[e[i].to]],dis[e[i].to]+dis[e[i].from]+e[i].w);
			}
		}F(i,1,p)pi(ans[x[i]]);
		return 0;
	}
}
signed main(){return EMT::main();}

真相

特判没有预言家的情况,直接O(n)扫。
否则设当前预言家是真话,记录当前预言家到上个预言家之间,说真话假话的人数。
把k相同的预言家合并,最后大力判断即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	inline void yes(){pf("consistent\n");}inline void no(){pf("inconsistent\n");}
	const int N=1e5+100;
	int opt[N],n,k[N],spj,fi[N],cntp;
	struct pt{int t,f,k;friend bool operator <(pt a,pt b){return a.k<b.k;}}p[N];
	inline bool check(){
		fi[1]=1;
		F(i,2,n)fi[i]=fi[i-1]^opt[i-1];
		if((fi[n]^opt[n])==fi[1])return 1;
		fi[1]=0;
		F(i,2,n)fi[i]=fi[i-1]^opt[i-1];
		if((fi[n]^opt[n])==fi[1])return 1;
		return 0;
	}
	inline short main(){
		//file();
		int T=read();
		while(T--){
			n=read();spj=cntp=0;
			F(i,1,n){
				char ch=getchar();while(ch!='$'&&ch!='+'&&ch!='-')ch=getchar();
				if(ch=='$')opt[i]=-1,k[i]=read(),spj=1;
				if(ch=='+')opt[i]=0;
				if(ch=='-')opt[i]=1;
			}
			if(!spj){check()?yes():no();continue;}
			F(i,1,n)if(opt[i]==-1){
				int j=i-1;j=j?j:n;
				p[++cntp]=(pt){1,0,k[i]};fi[i]=1;
				while(opt[j]!=-1){
					fi[j]=fi[j+1>n?1:j+1]^opt[j];
					if(fi[j])p[cntp].t++;else p[cntp].f++;
					j--;j=j?j:n;
				}
			}
			std::sort(p+1,p+cntp+1);
			int last=0;p[0].k=19260817;
			F(i,1,cntp){
				if(p[i].k==p[last].k)p[last].t+=p[i].t,p[last].f+=p[i].f,p[i].k=-1;
				else last=i;
			}
			int tot=0;bool fl1=0,fl2=0;
			F(i,1,cntp)if(p[i].k!=-1)tot+=p[i].f;
			F(i,1,cntp)if(p[i].k!=-1)if(p[i].k==tot-p[i].f+p[i].t)fl1=1;
			F(i,1,cntp)if(p[i].k==tot)fl2=1;
			(fl1||!fl2)?yes():no();
		}
		return 0;
	}
}
signed main(){return EMT::main();}

a

入镇曲双指针再现,前缀和满足单调,维护单调指针即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(ll x){pf("%lld ",x);}inline void pn(){pf("\n");}
	const int N=32,M=5e4+100;
	int pre[N][M],L,R,n,m,sum[M];ll ans;
	inline int get(int x,int y,int a,int b){return pre[a][b]-pre[a][y-1]-pre[x-1][b]+pre[x-1][y-1];}
	inline int gc(){char ch=getchar();while(ch!='0'&&ch!='1')ch=getchar();return ch-'0';}
	inline short main(){
		n=read(),m=read();
		F(i,1,n)F(j,1,m)pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+gc();
		L=read(),R=read();
		F(i,1,n)
			F(j,i,n){
				F(k,1,m)sum[k]=pre[j][k]-pre[i-1][k];
				int l=1,r=1;
				F(k,1,m){
					if(sum[k]>=L){
						while(sum[k]-sum[l-1]>R&&l+1<=k)l++;
						while(sum[k]-sum[r]>=L&&r+1<=k)r++;
						ans+=r-l+1;
					}
				}
			}
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

b

\(cnt_{i,j}\)表示第i行j出现的方案数,小小容斥+根号筛因子即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=23,M=1e5+100,inf=1e5,mod=1e9+7;
	int n,m,a[N][M],cnt[N][M],sum[M],ans;std::vector<int>s[M];
	inline short main(){
		//file();
		n=read(),m=read();
		F(i,1,n)F(j,1,m)a[i][j]=read();
		F(i,1,inf)
			F(j,1,sqrt(i))
				if(i%j==0){
					s[i].push_back(j);
					if(j*j!=i)s[i].push_back(i/j);
				}
		F(i,1,n)
			F(j,1,m)
				F(k,0,s[a[i][j]].size()-1)
					cnt[i][s[a[i][j]][k]]++;
		D(i,inf,1){
			sum[i]=1;
			F(j,1,n)sum[i]=1ll*sum[i]*(cnt[j][i]+1)%mod;
			sum[i]--;sum[i]+=sum[i]<0?mod:0;
		}
		D(i,inf,1){
			int pos=i<<1;
			while(pos<=inf)sum[i]-=sum[pos],sum[i]+=sum[i]<0?mod:0,pos+=i;
			(ans+=1ll*sum[i]*i%mod)%=mod;
		}pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

c

点分治,目前不会,尝试会一下
2021-08-13 21:13:54 星期五
写出来了,用点分治实现log的dp转移,对每条边保留至多3个颜色。
在lca上更新离线下来的答案,用vector记录边和边的颜色有哪些以及离线下来的问题。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=1e5+100;int siz[N],n,m,S,wt[N],rt,fa[N][22],deep[N],son[N],dp[N][5][5];bool vis[N];
	std::vector<std::pair<int,int>>s[N];int ans[N];
	std::vector<std::pair<int,std::vector<int>>>g[N];
	struct node{int id,x,y;};std::vector<node>rec[N];
	std::vector<int>col[N];
	inline void unique(int k,int fa){
		std::sort(s[k].begin(),s[k].end());
		s[k].erase(std::unique(s[k].begin(),s[k].end()),s[k].end());
		for(register int i=0,p=i+1;i<=(int)s[k].size()-1;i=p,p=i+1){
			int j=s[k][i].first;
			while(p<=(int)s[k].size()-1&&s[k][p].first==j)p++;
			if(j==fa)continue;
			g[k].push_back(std::make_pair(j,std::vector<int>()));
			g[j].push_back(std::make_pair(k,std::vector<int>()));
			F(l,i,min(p-1,i+2)){
				g[k].back().second.push_back(s[k][l].second);
				g[j].back().second.push_back(s[k][l].second);
			}
			unique(j,k);
		}
	}
	inline void findroot(int k,int fa){
		siz[k]=1;wt[k]=0;
		F(i,0,(int)g[k].size()-1){
			int j=g[k][i].first;
			if(j==fa||vis[j])continue;
			findroot(j,k);
			siz[k]+=siz[j];
			wt[k]=max(wt[k],siz[j]);
		}wt[k]=max(wt[k],S-siz[k]);
		if(wt[k]<wt[rt])rt=k;
	}
	inline void pre_lca(int k,int f){
		vis[k]=1;fa[k][0]=f;deep[k]=deep[f]+1;
		F(i,1,20)fa[k][i]=fa[fa[k][i-1]][i-1];
		F(i,0,(int)g[k].size()-1){
			int j=g[k][i].first;
			if(vis[j])continue;
			S=siz[j];wt[rt=0]=0x7fffffff;
			findroot(j,0);
			pre_lca(rt,k);
		}
	}
	inline int getlca(int a,int b){
		if(deep[a]<deep[b])a^=b^=a^=b;
		D(i,20,0)if((1<<i)<=deep[a]-deep[b])a=fa[a][i];
		if(a==b)return a;
		D(i,20,0)if(fa[a][i]!=fa[b][i])a=fa[a][i],b=fa[b][i];
		return fa[a][0];
	}
	inline void dfs(int k,int fa,int rtson){
		son[k]=rtson;
		F(i,0,(int)g[k].size()-1){
			int j=g[k][i].first;
			if(vis[j]||j==fa)continue;
			col[j]=g[k][i].second;
			F(t,0,(int)col[rtson].size()-1)
			F(l,0,(int)col[j].size()-1){
				dp[j][t][l]=-0x7fffffff;
				F(o,0,(int)col[k].size()-1)
				dp[j][t][l]=max(dp[j][t][l],dp[k][t][o]+(col[j][l]!=col[k][o]));
			}
			dfs(j,k,rtson);
		}
	}
	inline void solve(int k){
		vis[k]=1;
		F(i,0,(int)g[k].size()-1){
			int j=g[k][i].first;
			if(vis[j])continue;
			col[j]=g[k][i].second;
			F(t,0,(int)col[j].size()-1)
			F(l,0,(int)col[j].size()-1)
			dp[j][t][l]=t==l?1:-0x7fffffff;
			dfs(j,k,j);
		}
		F(i,0,(int)rec[k].size()-1){
			int x=rec[k][i].x,y=rec[k][i].y;
			if(y==k)x^=y^=x^=y;
			if(x==y)ans[rec[k][i].id]=0;
			else if(x==k){
				F(l,0,(int)col[son[y]].size()-1)
				F(t,0,(int)col[y].size()-1)
				ans[rec[k][i].id]=max(ans[rec[k][i].id],dp[y][l][t]);
			}else{
				F(sx,0,(int)col[son[x]].size()-1)
				F(sy,0,(int)col[son[y]].size()-1)
				F(l,0,(int)col[x].size()-1)
				F(t,0,(int)col[y].size()-1)
				ans[rec[k][i].id]=max(ans[rec[k][i].id],dp[x][sx][l]+dp[y][sy][t]-(col[son[x]][sx]==col[son[y]][sy]));
			}
		}
		F(i,0,(int)g[k].size()-1){
			int j=g[k][i].first;
			if(vis[j])continue;
			wt[rt=0]=0x7fffffff;S=siz[j];
			findroot(j,0);
			solve(rt);
		}
	}
	inline short main(){
		//file();
		n=read(),m=read();
		F(i,1,m){
			int x=read(),y=read(),z=read();
			s[x].push_back(std::make_pair(y,z));
			s[y].push_back(std::make_pair(x,z));
		}unique(1,0);
		S=wt[rt=0]=n;
		findroot(1,0);
		pre_lca(rt,0);
		int Q=read();
		F(i,1,Q){
			int x=read(),y=read();
			rec[getlca(x,y)].push_back((node){i,x,y});
		}
		memset(vis,0,sizeof(vis));
		S=wt[rt=0]=n;
		findroot(1,0);
		solve(rt);
		F(i,1,Q)pi(ans[i]),pn();
		return 0;
	}
}
signed main(){return EMT::main();}

打地鼠

考场上我和我的小伙伴都惊了!不说了,上n2

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=2e3+10;
	int a[N][N],n,k,ans;
	inline int gc(){char ch=getchar();while(ch!='0'&&ch!='1')ch=getchar();return ch-'0';}
	inline int get(int x,int y,int o,int i){
		return a[x][y]-a[x][i-1]-a[o-1][y]+a[o-1][i-1];
	}
	inline short main(){
		//file();
		n=read(),k=read();
		F(i,1,n)F(j,1,n)a[i][j]=gc();
		F(i,1,n)F(j,1,n)a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
		F(i,k,n)F(j,k,n)ans=max(ans,get(i,j,i-k+1,j-k+1));
		pi(ans);
		return 0;
	}
}
signed main(){return EMT::main();}

竞赛图

\(w_i\)表示当前集合向外的出边总集,于是转移一下即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=24;bool can[1<<N];int w[1<<N];
	inline short main(){
		int T=read();
		while(T--){
			int n=read();int all=(1<<n)-1;
			memset(can,1,sizeof(can));memset(w,0,sizeof(w));
			F(i,1,n)F(j,1,n)if(read())w[1<<(i-1)]|=1<<(j-1);
			w[0]=all;
			int ss;
			F(s,1,all)ss=s&-s,w[s]=w[s^ss]&w[ss];
			F(s,1,all)if(can[s])
			for(int i=w[s];i;(--i)&=w[s])can[s|i]=0;
			int ans=0;F(s,0,all)ans+=can[s];pi(ans);
			pn();
		}
		return 0;
	}
}
signed main(){return EMT::main();}

赛时就奔着首A去的,好耶
把问题转化成树上点一开始有一个权值,就是自己的编号,一个边如果两个端点权值不同,就是黑边,否则是白边,修改就是把路径上所有点改成一个新的权值,查询直接查即可,用树剖和线段树维护即可。

Code
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
namespace EMT{
	typedef long long ll;typedef double db;//(double)clock() / (double)CLOCKS_PER_SEC;
	#define pf printf
	#define F(i,a,b) for(register int i=a;i<=b;i++)
	#define D(i,a,b) for(register int i=a;i>=b;i--)
	inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
	inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
	inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
	inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
	const int N=3e5+100;int n,head[N],co,ti,tot,dfn[N],deep[N],fa[N],son[N],siz[N],top[N];
	struct node{int next,to;}e[N<<1];
	inline void add(int next,int to){e[++co].next=head[next],e[co].to=to,head[next]=co;}
	struct dp{int l,r,sum;}t[N<<2];
	struct seg{
		int lz[N<<2];
		inline void up(int p){
			t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
			if(t[p<<1].r!=t[p<<1|1].l)t[p].sum++;
			t[p].l=t[p<<1].l,t[p].r=t[p<<1|1].r;
		}
		inline void down(int p){
			if(lz[p]){
				t[p<<1].l=t[p<<1].r=t[p<<1|1].l=t[p<<1|1].r=lz[p<<1]=lz[p<<1|1]=lz[p];
				lz[p]=t[p<<1].sum=t[p<<1|1].sum=0;
			}
		}
		inline void change(int p,int l,int r,int ql,int qr,int v){
			if(l>=ql&&r<=qr){
				t[p].l=t[p].r=lz[p]=v;
				t[p].sum=0;
				return;
			}down(p);int mid=(l+r)>>1;
			if(qr<=mid)change(p<<1,l,mid,ql,qr,v);
			else if(ql>mid)change(p<<1|1,mid+1,r,ql,qr,v);
			else change(p<<1,l,mid,ql,mid,v),change(p<<1|1,mid+1,r,mid+1,qr,v);
			up(p);
		}
		inline dp ask(int p,int l,int r,int ql,int qr){
			if(l>=ql&&r<=qr)return t[p];
			int mid=(l+r)>>1;down(p);
			if(qr<=mid)return ask(p<<1,l,mid,ql,qr);
			if(ql>mid)return ask(p<<1|1,mid+1,r,ql,qr);
			dp a=ask(p<<1,l,mid,ql,mid),b=ask(p<<1|1,mid+1,r,mid+1,qr);
			dp ans;ans.l=a.l,ans.r=b.r;ans.sum=a.sum+b.sum;
			if(a.r!=b.l)ans.sum++;
			return ans;
		}
		inline void build(int p,int l,int r){
			if(l==r){t[p].l=t[p].r=l,t[p].sum=0;return;}
			int mid=(l+r)>>1;
			build(p<<1,l,mid);build(p<<1|1,mid+1,r);
			up(p);
		}
	}segm;
	struct trp{
		inline void dfs1(int k,int f){
			siz[k]=1;
			for(register int i=head[k];i;i=e[i].next){
				int j=e[i].to;if(j==f)continue;
				fa[j]=k;deep[j]=deep[k]+1;
				dfs1(j,k);siz[k]+=siz[j];
				if(siz[son[k]]<siz[j])son[k]=j;
			}
		}
		inline void dfs2(int k,int tp){
			dfn[k]=++ti;top[k]=tp;
			if(!son[k])return;
			dfs2(son[k],tp);
			for(register int i=head[k];i;i=e[i].next)
				if(e[i].to!=fa[k]&&e[i].to!=son[k])
					dfs2(e[i].to,e[i].to);
		}
	}sp;
	inline void change(int x,int y){
		int fx=top[x],fy=top[y];
		while(fx!=fy){
			if(deep[fx]>=deep[fy])segm.change(1,1,n,dfn[fx],dfn[x],tot),x=fa[fx];
			else segm.change(1,1,n,dfn[fy],dfn[y],tot),y=fa[fy];
			fx=top[x],fy=top[y];
		}
		if(deep[x]>=deep[y])segm.change(1,1,n,dfn[y],dfn[x],tot);
		else segm.change(1,1,n,dfn[x],dfn[y],tot);
	}
	inline int get(int x,int y){
		int fx=top[x],fy=top[y],ans=0;
		while(fx!=fy){
			if(deep[fx]>=deep[fy]){
				dp s=segm.ask(1,1,n,dfn[fx],dfn[x]),sf=segm.ask(1,1,n,dfn[fa[fx]],dfn[fa[fx]]);
				ans+=s.sum;if(sf.l!=s.l)ans++;x=fa[fx];
			}else{
				dp s=segm.ask(1,1,n,dfn[fy],dfn[y]),sf=segm.ask(1,1,n,dfn[fa[fy]],dfn[fa[fy]]);
				ans+=s.sum;if(sf.l!=s.l)ans++;y=fa[fy];
			}fx=top[x];fy=top[y];
		}dp s;
		if(deep[x]>=deep[y])s=segm.ask(1,1,n,dfn[y],dfn[x]);else s=segm.ask(1,1,n,dfn[x],dfn[y]);
		ans+=s.sum;return ans;
	}
	inline short main(){
		//file();
		n=read();tot=n;
		F(i,1,n-1){
			int x=read(),y=read();
			add(x,y);add(y,x);
		}sp.dfs1(1,0);sp.dfs2(1,1);segm.build(1,1,n);
		int Q=read();
		F(i,1,Q){
			int opt=read();
			if(opt==1){
				int x=read(),y=read();tot++;
				change(x,y);
			}else{
				int x=read(),y=read();
				pi(get(x,y));pn();
			}
		}
		return 0;
	}
}
signed main(){return EMT::main();}
posted @ 2021-07-21 09:38  letitdown  阅读(171)  评论(6编辑  收藏  举报