UR #19 简要题解

比赛总结

开场把 \(\text{T1}\) 读成一道不可做,然后又成功写完 \(\text{T2}\)\(log\) 的做法后以为过不了,并且成功的傻逼的以为正确的 \(n^3\) 做法思路没法做,以至 \(2.5h\) 后才写完两道的 \(170\)。最后十分钟才发现自己读错题,只好打出 \(\text{GG}\)

省选这样的话就可以退役了。

T1

\(m+1\) 的限制不用管。可以发现如果只有环的操作充要条件是只考虑 \(1\) 的边度数全部相等。于是变量就只有 \(n\) 个。二分图可以拆成每个点分别操作。

高斯消元即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 510;
bitset<N> b[N];

int n,m,deg[N],val[N];

void guass(){
	for(int i=1;i<=n;i++){
		if(!b[i][i]){
			int p=0;
			for(int j=i+1;j<=n;j++)if(b[j][i]){p=j;break;}
			if(!p)continue;
			swap(b[i],b[p]);
		}
		for(int j=1;j<=n;j++)if(i^j){
			if(b[j][i])b[j]^=b[i];
		}
	}
	for(int i=1;i<=n;i++)if(!b[i][i]&&b[i][n+1]){
		puts("no");
		return ;
	}
	puts("yes");
}

void Main(){
	cin >> n >> m;
	for(int i=1;i<=n;i++)b[i].reset();
	for(int i=1;i<=n;i++)deg[i]=0,val[i]=0;
	for(int i=1;i<=m;i++){
		int u,v,w;scanf("%d%d%d",&u,&v,&w);
		b[u][v] = b[v][u] = 1;
		deg[u]^=1,deg[v]^=1;
		if(w)val[u]^=1,val[v]^=1;
	}
	for(int i=1;i<=n;i++)b[i][i]=deg[i],b[i][n+1]=val[i];
	guass();
}

int main()
{
	int T;cin >> T;
	while(T--){
		Main();
	}
}

T2

简要题解:猎人杀,没了

拆成每个点的贡献,之后就是这个位置需要 \(a\) 个,其它位置需要 \(b\) 个,概率就是这个位置不是最后填满的概率。

容斥之后发现只需要算 \(f_{i,j}\) 表示 \(i\) 个人分 \(j\) 个东西,人和东西有标号,每个人不能分到 \(\ge b\) 个。

\(NTT\) 去做背包即可 \(O(n^3\log n)\)

当然这个有一个 \(O(n^3)\)\(\text{dp}\),我们考虑最后一个物品放给谁,然后现在不合法的情况只有一种:某个人分到了恰好 \(b\) 个。

然后转移就是 \(O(1)\) 的了。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
int sub(int a,int b){a-=b;return a<0?a+mod:a;}
int mul(int a,int b){return (ll)a*b%mod;}
int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
/* math */
int n,a,b;

typedef vector<int> Poly;
namespace Ploy_template {
	int rev[4000010];
	Poly Add(Poly a,Poly b){
		a.resize(max(a.size(),b.size()));
		for(size_t i=0;i<b.size();i++)a[i] = add(a[i],b[i]);
		return a;
	}
	Poly Sub(Poly a,Poly b){
		a.resize(max(a.size(),b.size()));
		for(size_t i=0;i<b.size();i++)a[i] = sub(a[i],b[i]);
		return a;
	}
	Poly rever(Poly x){
		reverse(x.begin(),x.end());
		return x;
	}
	inline void DFT(int *t,int n,int tpe){
		int l=0;while(1<<l<n)++l;
		for(int i=1;i<n;i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<(l-1));
		for(int i=0;i<n;i++) if(rev[i]>i) swap(t[rev[i]],t[i]);
		for(int step=1;step<n;step<<=1){
			int wn = qpow(3, (mod-1)/(step<<1));
			for(int i=0;i<n;i+=step<<1){
				int w = 1;
				for(int j=0;j<step;j++,w = mul(w,wn)){
					int x = t[i+j], y = mul(w,t[i+j+step]);
					t[i+j] = add(x,y); t[i+j+step] = sub(x,y);
				}
			}
		}
		if(tpe==1)return ;
		for(int i=1;i<n-i;i++)swap(t[i],t[n-i]);
		int inv = qpow(n,mod-2);
		for(int i=0;i<n;i++)t[i] = mul(t[i], inv);
	}
	inline Poly NTT(Poly a, int n, Poly b, int m){
		int len = n+m-1,l=0;while(1<<l<len)++l;
		static Poly res;
		res.resize(1<<l); a.resize(1<<l),b.resize(1<<l);
		DFT(&a[0],1<<l,1),DFT(&b[0],1<<l,1);
		for(int i=0;i<(1<<l);i++)res[i] = mul(a[i],b[i]);
		DFT(&res[0],1<<l,-1);
		res.resize(len);
		return res;
	}
	Poly NTT(Poly a, Poly b){
		return NTT(a,a.size(),b,b.size());
	}
}
using namespace Ploy_template;

const int N = 260;
int ifac[N*N],fac[N*N];
inline void init(int n=250*260){
	ifac[0]=fac[0]=1;for(int i=1;i<=n;i++)fac[i]=mul(fac[i-1],i);
	ifac[n]=qpow(fac[n],mod-2);for(int i=n-1;i;i--)ifac[i]=mul(ifac[i+1],i+1);
}
Poly f;
Poly g[N];

inline int binom(int a,int b){
	if(a<b)return 0;
	return mul(fac[a],mul(ifac[b],ifac[a-b]));
}

void output(Poly& t){
	for(size_t i=0;i<t.size();i++)cout << t[i] << " ";puts("");
}

Poly multar(Poly a,Poly b){
	Poly c(a.size(),0);
	for(size_t i=0;i<a.size();i++)c[i]=mul(a[i],b[i]);
	return c;
}

int main()
{
	init();
	cin >> n >> a >> b;
	f.resize(b);
	for(int i=0;i<b;i++)f[i] = ifac[i];
	int Lenth = (n-1)*(b-1)+1;
	int len = 1;
	while(Lenth>len)len<<=1;
	f.resize(len);
	DFT(&f[0],len,1);
	g[0].resize(len);
	for(int i=0;i<len;i++)g[0][i]=1;
	for(int i=1;i<=n-1;i++)g[i]=multar(g[i-1],f);
	int ret=0;//for debug
	for(int i=0;i<n;i++){
		DFT(&g[i][0],len,-1);
		int d = qpow(i+1,mod-2);
		int P = qpow(d,a);
		P=mul(P,binom(n-1,i));
		if(i&1){P=sub(0,P);}
		for(int j=0;j<len;j++){
			int q = mul(g[i][j],fac[j]);
			q = mul(q, binom(a-1+j,a-1));
			q=mul(P,q);
			ret=add(ret,q);
			P=mul(P,d);
		}
	}
	cout << mul(sub(1,ret),n) << endl;
}

T3

从后向前,维护下标为时间的后缀 \(min\) 以及修改次数。

这玩意是 Segment Tree Beats。

代码(被卡常)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+6;


namespace FastIO {
	#define SIZE 100000
	inline char nc(){
		// return getchar();
		static char buf[SIZE],*p1=buf+SIZE,*p2=buf+SIZE;
		if(p1==p2) p2=(p1=buf)+fread(buf,1,SIZE,stdin);
		return p1==p2?-1:*p1++;
	}
	inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
	template <class T> inline void read(T &x){
		register double tmp = 1;
		register bool sign = 0;
		x = 0;
		register char ch=nc();
		for(;ch<'0'||ch>'9';ch=nc()) if(ch=='-') sign=1;
		for(;ch>='0'&&ch<='9';ch=nc()) x=x*10+ch-'0';
		if(ch=='.') for(ch=nc();ch>='0'&&ch<='9';ch=nc()) tmp/=10.0,x+=tmp*(ch-48);
		if(sign) x=-x;
	}
	inline void read(char *s){
		register char ch=nc();
		for (;blank(ch);ch=nc());
		for (;!blank(ch);ch=nc()) *s++=ch;
		*s=0;
	}
	inline void read(char &c){
		for(c=nc();blank(c);c=nc());
	}
	template <class T> inline void print(T x){
		if(x<0) putchar('-'),x=-x;
		if(x>9) print(x/10);
		putchar('0'+x%10);
	}
	template <class T> inline void print(T x,char c){
		print(x),putchar(c);
	}
}
using namespace FastIO;

int n,m;
struct dat{
	int mx,secmx,Add;
}t[N<<2];

#define mid ((l+r)>>1)
inline void pushup(int x){
	if(t[x<<1].mx>t[x<<1|1].mx){
		t[x].mx=t[x<<1].mx;
		t[x].secmx=max(t[x<<1].secmx,t[x<<1|1].mx);
	}else{
		t[x].mx=t[x<<1|1].mx;
		if(t[x<<1].mx==t[x<<1|1].mx){
			t[x].secmx=max(t[x<<1|1].secmx,t[x<<1].secmx);
		}else t[x].secmx=max(t[x<<1|1].secmx,t[x<<1].mx);
	}
}
inline void adval(int x,int val,int Ad){
	if(t[x].mx>val){
		t[x].mx=val;
		t[x].Add+=Ad;
	}
}
inline void pushdown(int x){
	if(t[x].Add){
		adval(x<<1,t[x].mx,t[x].Add);
		adval(x<<1|1,t[x].mx,t[x].Add);
		t[x].Add=0;
	}
}

inline void build(int x,int l,int r){
	t[x].mx=1<<30, t[x].secmx=-(1<<30);
	if(l==r)return ;
	build(x<<1,l,mid),build(x<<1|1,mid+1,r);
}

inline void Ad(int x,int x1){
	if(t[x].secmx<x1){
		adval(x,x1,1);return ;
	}pushdown(x);
	Ad(x<<1,x1);
	Ad(x<<1|1,x1);
	pushup(x);
}

inline void modify(int x,int l,int r,int ql,int qr,int v){
	// if(x==1)cout << ql << " " << qr << " " << v << endl;
	if(ql<=l&&qr>=r){Ad(x,v);return;}
	pushdown(x);
	if(ql<=mid)modify(x<<1,l,mid,ql,qr,v);
	if(qr>mid) modify(x<<1|1,mid+1,r,ql,qr,v);
	pushup(x);
}

inline int query(int x,int l,int r,int p){
	if(l==r)return t[x].Add;
	pushdown(x);
	if(p<=mid)return query(x<<1,l,mid,p);
	else return query(x<<1|1,mid+1,r,p);
}
typedef pair<int,int> pi;
pair<int, pair<pi,int> > opt[N<<1];
int c1;
int a[N];int lst[N];
pair<int,pi> q[N];
int c2;
int ans[N];

int M=1;

int main()
{
	read(n),read(m);
	build(1,1,m);
	for(int i=1;i<=n;i++){
		read(a[i]);
		lst[i]=1;
	}
	for(int i=1,op,x,v;i<=m;i++){
		read(op);
		ans[i] = -1;
		if(op==1){
			read(x),read(v);
			opt[++c1]=make_pair(x,make_pair(pi(lst[x],M),a[x]));
			a[x] = v;
			lst[x]=++M;
		}else{
			read(x);
			q[++c2]=make_pair(x,make_pair(M,i));
		}
	}
	for(int i=1;i<=n;i++){
		opt[++c1]=make_pair(i,make_pair(pi(lst[i],M),a[i]));
	}
	sort(opt+1,opt+c1+1),sort(q+1,q+c2+1);
	build(1,1,M);
	for(int i=n,l,r,v;i;i--){
		while(c1&&opt[c1].first==i){
			l=opt[c1].second.first.first,r=opt[c1].second.first.second,v=opt[c1].second.second;
			if(l<=r)modify(1,1,M,l,r,v);
			--c1;
		}
		while(c2&&q[c2].first==i){
			ans[q[c2].second.second]=query(1,1,M,q[c2].second.first);
			--c2;
		}
	}
	for(int i=1;i<=m;i++){
		if(ans[i]!=-1){
			print(ans[i],'\n');
		}
	}
}
posted @ 2020-04-05 16:30  jerome_wei  阅读(299)  评论(0编辑  收藏  举报