2.7模拟总结

前言

130pts
20+100+10
终于没有挂分!
开心!
然而今天的题确实过于阴间…三道题几乎都没法写暴力,爆零场了属于是。
我这个分数都能到rnk4勒。
(rnk39->rnk4,乐)

考场

一拿题我就觉得不太妙。
T1数树题,第一眼看到输入一个数输出一个数就想到应该是生成函数+多项式,但是不给NTT模数?
难道这玩意能dp?
…本场满分200分。
T2看起来还挺正常的,把二分写脸上了。
T3题如其名,动态沙漠玩期望,《毒瘤》,我突然发现自己仙人掌是一道题都没做过,感觉可能要LCT罢,但是那个期望我也没什么想法…本场满分100分。

20min,我差不多明白了本场考试的阴间,决定死磕T1了,感觉拿下的话应该也不会太差。
(但是由于前两天的《优异表现》,加上T2无法对拍,我也做好了爆零的心理准备)
稍微分析了一下发现这个T2是相当可做,二分完答案后从度数的角度入手变成了一个网络流模型,然后这个网络流还是二分图,点边级别都是 O ( m ) O(m) O(m),这样单次check函数 O ( m m ) O(m\sqrt m) O(mm ),挂个二分的log似乎就过了?

然后就开始写。
不太难写,不久就写完了。没有对拍心乱如麻…
然后就写了个环的datamaker,然后在代码里疯狂assert
自己拍自己了属于是
拍了一下发现自环的定向似乎有锅,加了个特判。
(“自环的定向”这东西本身就离谱,其实只是我的assert锅了,答案不会出错。)
然后再拍似乎就没啥问题了。

然后还有俩点,就去瞅瞅T1/3吧。

一看T3数据:k=0?大喜过望:我会并查集!
就这样十分到手。

再看T1。
越看越蒙,我甚至连它是个什么算法都没有头绪,难道真是dp?
但是这种单输入题不就是给打表准备的嘛,开始试图骗20分。
如何枚举有标号森林形态?
写个dfs,枚举当前的结点和之前哪个结点连边,然后与每片森林最多连一条边,整个带撤销并查集就可以了。比想象中好写不少。
要是无标号我恐怕就真不会了,似乎得从重心入手,可能得树哈希?
n<=10跑的飞快,8s就把我的表打出来了。
填到数组里一交20分到手=v=。
为了让我的代码显得厚重一点还把暴搜贴进去不调用一起交上去了。

然后还有一个多小时。
又又又又检查了一下T2,然后实在没有事干,就去看上午回放了。
没啥大变化,几乎和去年的视频还是一样的,就是声音变成男生了,还不如女声好听,但讲课节奏能更舒服一些。
也有收获吧,把构造最小点覆盖的方法揉到网络流整理里面了,之前第一次看我没有理解那个。
再看关押犯人那个模型还是觉得不如开虚点…

题目解析

T1

科技题。
Prufer 序列我确实不会啊…
补了两个月科技,竟然又被卡科技了?
qwq
Prufer序列就是听着高大上,其实还是挺简单的。
简洁而强大,这就是优雅。

答案可以通过1号点的贡献乘n得到。
一个重要的处理技巧是枚举1号点所在的联通块大小
套点组合数后面的式子就比较显然了。

T2

做的还是不错的。
感觉题解的建图还没有我的建图简洁

T3

真心毒瘤题。
首先是一个trick:用LCT维护圆方树。
前几天还做过一道需要这个方法的
然后处理那个期望的关键是:连通块数=点数-边数+环数
然后由于期望的线性性可以分别求解(可以说把线性性用的出神入化了)。
求黑环的期望的时候需要一个容斥。然而我发现自己讲不清楚这个容斥怎么来的,就去补了一下容斥的基础。
其实它啥也不是,就是朴素容斥而已。
感觉这两天把期望和容斥这两块基础补了还是不错的。

代码

T1 forest

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read(){
	ll x(0),f(1);char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int N=5e3+100;
const int M=2e5+100;
const int inf=1e9;

int mod;
inline ll ksm(ll x,ll k){
	ll res(1);
	while(k){
		if(k&1) res=res*x%mod;
		k>>=1;
		x=x*x%mod;
	}
	return res;
}

int n,m;

ll jc[N],ni[N];
inline ll C(int n,int m){
	return jc[n]*ni[m]%mod*ni[n-m]%mod;
}
ll f[N],g[N],s[N],ans[N];
void init(){
	n=5000;
	jc[0]=1;
	for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod;
	ni[n]=ksm(jc[n],mod-2);
	for(int i=n-1;i>=0;i--) ni[i]=ni[i+1]*(i+1)%mod,assert(ni[i]*jc[i]%mod==1);
	
	f[1]=1;
	for(int i=2;i<=n;i++) f[i]=ksm(i,i-2);
	g[0]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++) g[i]=(g[i]+f[j]*C(i-1,j-1)%mod*g[i-j])%mod;
	}
	s[1]=0;
	for(int i=2;i<=n;i++){
		ll b=ksm(i-1,i-1);
		for(int j=1;j<i;j++){
			b=b*ni[i-1]%mod*jc[i-2]%mod;
			s[i]=(s[i]+1ll*j*j%mod*C(i-2,j-1)%mod*b)%mod;
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++) ans[i]=(ans[i]+s[j]*C(i-1,j-1)%mod*g[i-j])%mod;
		ans[i]=ans[i]*i%mod;
	}
	//printf("f: ");for(int i=1;i<=n;i++) printf("%lld ",f[i]);puts("");
	//printf("g: ");for(int i=1;i<=n;i++) printf("%lld ",g[i]);puts("");
	//printf("s: ");for(int i=1;i<=n;i++) printf("%lld ",s[i]);puts("");
	//printf("ans: ");for(int i=1;i<=n;i++) printf("%lld ",ans[i]);puts("");
	return;
}

signed main(){
	freopen("forest.in","r",stdin);
	freopen("forest.out","w",stdout);
	//debug("%d\n",(int)sizeof(mi)/1024/1024);
	int T=read();mod=read();
	init();
	while(T--){
		printf("%lld\n",ans[read()]);
	}
	return 0;
}
/*
4 3
1 2 1 1
2 3 1 1
3 1 1 1 
*/
 

T2 euler

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read(){
	ll x(0),f(1);char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int N=4e4+100;
const int M=2e5+100;
const int inf=1e9;
const double eps=1e-10;

int n,m;

int s,t,tot;
struct node{
	int to,nxt,cap;
}p[M<<1];
int fi[N],cur[N],cnt;
inline void addline(int x,int y,int c){
	p[++cnt]=(node){y,fi[x],c};fi[x]=cnt;
}
inline void add(int x,int y,int c){
	//printf("add: %d-> %d cap=%d\n",x,y,c);
	addline(x,y,c);addline(y,x,0);
}
int bel[N];
queue<int>q;
int bfs(){
	fill(bel,bel+1+tot,0);
	bel[s]=1;q.push(s);
	while(!q.empty()){
		int now=q.front();q.pop();
		//printf("now=%d\n",now);
		for(int i=cur[now]=fi[now];~i;i=p[i].nxt){
			int to=p[i].to;
			if(bel[to]||!p[i].cap) continue;
			bel[to]=bel[now]+1;
			q.push(to);
		}
	}
	return bel[t];
}
int dfs(int x,int lim){
	if(!lim||x==t) return lim;
	int res(0);
	for(int &i=cur[x];~i;i=p[i].nxt){
		int to=p[i].to;
		if(bel[to]!=bel[x]+1) continue;
		int add=dfs(to,min(lim,p[i].cap));
		res+=add;lim-=add;
		p[i].cap-=add;p[i^1].cap+=add;
		if(!lim) break;
	}
	if(!res) bel[x]=-1;
	return res;
}
int dinic(){
	int flow(0),tmp(0);
	while(bfs()){//ok;
		while((tmp=dfs(s,inf))) flow+=tmp;
	}
	//printf("flow=%d\n",flow);
	return flow;
}

int fa[N];
int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}

int du[N];
int u[N],v[N],v1[N],v2[N];
int que[N<<1],num;
bool check(int k){
	k=que[k];
	//printf("check: k=%d\n",k);
	memset(fi,-1,sizeof(fi));cnt=-1;
	tot=m+n;s=++tot;t=++tot;
	for(int i=1;i<=m;i++){
		add(s,i,1);
		if(v1[i]<=k) add(i,v[i]+m,1);
		if(v2[i]<=k) add(i,u[i]+m,1);
	}
	for(int i=1;i<=n;i++){
		if(du[i]&1) return false;
		add(i+m,t,du[i]/2);
	}
	return dinic()==m;
}

int x[N],y[N];
int ans[N],top;
void oula(int x,int frm){
	for(int i=fi[x];~i;i=fi[x]){
		int to=p[i].to;
		fi[x]=p[i].nxt;
		oula(to,p[i].cap);
	}
	if(frm) ans[++top]=frm;
	return;
}

signed main(){
	freopen("euler.in","r",stdin);
	freopen("euler.out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=n;i++) fa[i]=i;
	//int block=n;
	for(int i=1;i<=m;i++){
		u[i]=read();v[i]=read();v1[i]=read();v2[i]=read();
		du[u[i]]++;du[v[i]]++;
		que[++num]=v1[i];que[++num]=v2[i];
		if(find(u[i])!=find(v[i])){
			fa[find(u[i])]=find(v[i]);
			//block--;
		}
	}
	
	int id(0);
	for(int i=1;i<=n;i++){
		if(!du[i]) continue;
		if(!id) id=find(i);
		else if(id!=find(i)){
			//assert(0);
			//debug("NIE\n");
			puts("NIE");return 0;
		}
	}
	
	sort(que+1,que+1+num);
	num=unique(que+1,que+1+num)-que-1;
	que[num+1]=que[num]+1;
	
	//check(num+1);return 0;

	int st=1,ed=num+1;
	while(st<ed){
		int mid=(st+ed)>>1;
		if(check(mid)) ed=mid;
		else st=mid+1;
	}
	if(st==num+1){
		//assert(0);
		//debug("NIE\n");
		puts("NIE");return 0;
	}
	check(st);
	//int mx(0);
	for(int i=1;i<=m;i++){
		for(int j=fi[i];~j;j=p[j].nxt){
			int to=p[j].to;
			if(to==s||p[j].cap) continue;
			to-=m;
			//if(u[i]==v[i]) mx=max(mx,min(v1[i],v2[i]));
			//else if(to==u[i]) mx=max(mx,v2[i]);
			//else mx=max(mx,v1[i]);
			if(to==u[i]){				
				x[i]=v[i],y[i]=u[i];
			}
			else{				
				//assert(to==v[i]);
				x[i]=u[i],y[i]=v[i];
			}
		}
		//assert(x[i]);
	}
	//debug("mx=%d ans=%d\n",mx,que[st]);
	//assert(mx==que[st]);
	memset(fi,-1,sizeof(fi));cnt=-1;
	for(int i=1;i<=m;i++) addline(x[i],y[i],i);
	for(int i=1;i<=n;i++){
		if(du[i]){
			oula(i,0);break;
		}
	}
	if(top!=m){
		//assert(0);
		puts("NIE");return 0;
	}
	printf("%d\n",que[st]);
	while(top) printf("%d ",ans[top--]);
	return 0;
}
/*
4 3
1 2 1 1
2 3 1 1
3 1 1 1 
*/
 

T3 graph

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read(){
	ll x(0),f(1);char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int N=6e5+100;
const int M=2e5+100;
const int inf=1e9;
const int mod=998244353;

inline ll ksm(ll x,ll k){
	ll res(1);
	while(k){
		if(k&1) res=res*x%mod;
		k>>=1;
		x=x*x%mod;
	}
	return res;
}

int n,m;
int id,E,o,k;

int tr[N][2],sum[N],val[N],f[N],rev[N];
inline bool nroot(int x){
	return tr[f[x]][0]==x||tr[f[x]][1]==x;
}
inline bool which(int x){
	return tr[f[x]][1]==x;
}
inline void pushup(int x){
	if(x) sum[x]=sum[tr[x][0]]+sum[tr[x][1]]+val[x];
	return;
}
inline void Rev(int x){
	if(x){
		rev[x]^=1;
		swap(tr[x][0],tr[x][1]);
	}
}
inline void pushdown(int x){
	if(rev[x]){
		rev[x]=0;
		Rev(tr[x][0]);Rev(tr[x][1]);
	}
}
inline void rotate(int x){
	int fa=f[x],gfa=f[fa];
	int d=which(x),son=tr[x][d^1];
	f[x]=gfa;if(nroot(fa)) tr[gfa][which(fa)]=x;
	f[fa]=x;tr[x][d^1]=fa;
	if(son){f[son]=fa;}tr[fa][d]=son;
	pushup(fa);pushup(x);
}
int zhan[N];
inline void splay(int x){
	int y(x),top(0);
	zhan[++top]=y;
	while(nroot(y)) zhan[++top]=y=f[y];
	while(top) pushdown(zhan[top--]);
	for(int fa;fa=f[x],nroot(x);rotate(x)){
		if(nroot(fa)) which(fa)==which(x)?rotate(fa):rotate(x);
	}
	return;
}
inline void access(int x){
	for(int y=0;x;y=x,x=f[x]){
		splay(x);
		tr[x][1]=y;
		pushup(x);
	}
}
inline void makeroot(int x){
	access(x);splay(x);Rev(x);
}
inline int findroot(int x){
	access(x);splay(x);
	while(pushdown(x),tr[x][0]) x=tr[x][0];
	return x;
}
inline void split(int x,int y){
	makeroot(x);access(y);splay(y);
}
inline void link(int x,int y){
	makeroot(x);makeroot(y);
	f[x]=y;
}
inline void cut(int x,int y){
	split(x,y);
	f[x]=tr[y][0]=0;
	pushup(y);
}
int a[N],num;
void dfs(int x){
	if(!x) return;
	pushdown(x);
	dfs(tr[x][0]);
	a[++num]=x;
	dfs(tr[x][1]);
	return;
}
inline void add(int x,int y){
	num=0;
	if(findroot(x)!=findroot(y)) link(x,y),++E;
	else{
		split(x,y);
		if(sum[y]) return;
		++E;
		int now=++id;
		val[id]=sum[id]=1;
		dfs(y);
		for(int i=1;i<num;i++) cut(a[i],a[i+1]);
		for(int i=1;i<=num;i++) link(now,a[i]);
		return;
	}
}
ll w[N],b[N];
ll jc[N],ni[N];
inline ll C(int n,int m){
	return jc[n]*ni[m]%mod*ni[n-m]%mod;
}
void init(){
	jc[0]=1;
	for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod;
	ni[n]=ksm(jc[n],mod-2);
	for(int i=n-1;i>=0;i--) ni[i]=ni[i+1]*(i+1)%mod;//assert(ni[i]*jc[i]%mod==1);
	ll bas=ksm(ksm(n,k),mod-2);
	for(int x=0;x<=n;x++){
		w[x]=ksm(n-x,k)*bas%mod;
		//printf("x=%d w=%lld\n",x,w[x]);
	}
	return;
}
inline ll B(int x){
	if(b[x]!=-1) return b[x];
	ll res(0);
	for(int i=0;i<=x;i++){
		res=(res+((i&1)?-1:1)*C(x,i)*w[i]%mod+mod)%mod;
	}
	//printf("x=%d b=%lld\n",x,res);
	return b[x]=res;
}

int lst(0);
ll now;
signed main(){
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
	id=n=read();m=read();k=read();o=read();
	init();
	memset(b,-1,sizeof(b));
	now=n*(w[1]+o*B(1))%mod;
	//printf("---%lld %lld+%d*%lld\n",w[1]+o*B(1),w[1],o,B(1));
	while(m--){
		int x=read()^lst,y=read()^lst;
		//printf("(%d %d)\n",x,y);
		if(x==y){
			printf("%d\n",lst);
			continue;
		}
		add(x,y);
		if(num) now=(now+w[num]+o*B(num))%mod;
		lst=(now-E*(w[2]+o*B(2))%mod+mod)%mod;
		//printf("  E=%d num=%d now=%lld\n",E,num,now);
		printf("%d\n",lst);
	}
	return 0;
}
/*
4 3
1 2 1 1
2 3 1 1
3 1 1 1 
*/
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值