[考试总结]noip模拟48

今天题目比较简单,所以有时间来写博客。。。

然后先从模拟48开始

啊这。。。。

记不太清自己的考场行为了,就简单说说题解吧。。。

lighthouse

这个就是一个挺简单的容斥,然后一个环排列就有了。

系数为 \((-1)\)



#include<bits/stdc++.h>
using std::endl; using std::cout;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
#define asm(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
	#define debug cout<<"debug"<<endl
	#define sb(x) cout<<#x" = "<<x<<' '
	#define jb(x) cout<<#x" = "<<x<<endl
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1 ++
	char buf[1<<20],*p1 = buf,*p2 = buf; typedef long long ll; typedef unsigned long long ull;
	class xin_stream{public:template<typename type>xin_stream &operator >> (type &s)
	{
		register bool f = 0; s = 0; register char ch = gc();
		while(!isdigit(ch)) f |= ch == '-',ch = gc();
		while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch xor 48),ch = gc(); return s = f ? -s : s,*this;
	}}io;
}
using namespace xin_io; static const int maxn = 1e7+10,inf = 1e9+10;
#define int long long
namespace xin
{
	const int mod = 1e9+7;
	int fac[maxn],n,m;
	inline void pre_work() {fac[0] = 1; try(i,1,n) fac[i] = fac[i-1] * i % mod;}
	inline int ksm(int x,int y) 
	{
		register int ret = 1;
		while(y)
		{
			if(y & 1) ret = ret * x % mod;
			x = x * x % mod; y >>= 1;
		}
		return ret;
	}
	inline int count(int x)
	{
		int ret = 0;
		while(x) ret += (x & 1),x >>= 1;
		return ret;
	}
	class xin_data
	{
		public:
			int x,y;
			xin_data(){}
			xin_data(int x,int y):x(x),y(y){}
	}d[maxn]; int zhi = 0;
	int ans = 0;
	int fa[maxn],q[maxn],top;
	inline int find(int x) {return fa[x] == x ? x : fa[x] = find(fa[x]);}
	inline void merge(int x,int y) 
	{
		if(x == y) return ;
		fa[x] = y;
	}
	bool ji[maxn],shit[maxn];
	int vis[maxn];
	inline int work(int st)
	{
//		memset(vis,0,sizeof(bool) * (n + 1)); memset(fa,0,sizeof(int) * (n + 1));
//		memset(ji,0,sizeof(bool) * (n + 1)); memset(shit,0,sizeof(bool) * (n + 1));
		try(i,1,zhi) if((st >> (i - 1) & 1)) vis[d[i].x] = vis[d[i].y] = ji[d[i].x] = ji[d[i].y] = 0;
		int ok = 0,temp = 0,zhuan = 0; top = 0; register int num = count(n);
		try(i,1,zhi)
			if(((st >> (i - 1)) & 1))
			{
				register int x = d[i].x,y = d[i].y;
				shit[x] = 1; shit[y] = 1; 
				fa[x] = x; fa[y] = y;
				q[++top] = i;
			}
//		try(i,1,n) if(!shit[i]) fa[i] = 0;
		try(i,1,top)
		{
			register int x = d[q[i]].x,y = d[q[i]].y,fx = find(d[q[i]].x),fy = find(d[q[i]].y);
			temp += !vis[x] + !vis[y];
			if(fx == fy) ok = 1; merge(fx,fy);
			if(vis[x] > 1 or vis[y] > 1) return 0;
			vis[x] ++;  vis[y] ++;
		}
		try(i,1,top) 
		{
			register int x = find(d[q[i]].x);
			if(!ji[x]) ji[x] = 1,zhuan++;
		}
		if(ok) if((zhuan > 1) or(num xor n)) return 0;
//		sb(zhuan); jb(num);
		int ret = fac[n + zhuan - temp - 1] * ksm(2,zhuan) % mod * ksm(2,mod - 2) % mod;
		return ret;
	}
	bool fuck[maxn];
	inline short main()
	{
		io >> n >> m;
/*		if(!m)
		{
			ans = 1;
			try(i,1,n) ans = ans * i % mod;
			cout<<ans<<endl;
			return 0;
		}*/
		try(i,1,n) fa[i] = i; int face;
		try(i,1,m)
		{
			register int x,y; io >> x >> y;
			d[++zhi] = xin_data(x,y);
			merge(find(x),find(y));
			face = x;
		}
		int jsq = 0;
		try(i,1,n) if(!fuck[find(i)]) fuck[find(i)] = 1,jsq ++;
		if(jsq == 1) {ans += (n >= 20 or (n == m and face == 3)); if(n <= 10 and m>=20) {cout<<0<<endl; return 0;}}
		pre_work();
		try(i,0,(1 << zhi) - 1) 
		{
			if(count(i) & 1) //ji
				ans = (ans - work(i) + mod) % mod;
			else // ou
				ans = (ans + work(i) + mod) % mod;
		}
		cout<<(ans + mod) % mod<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

Minner

欧拉回路

假设图中有 \(k\)个联通块,然后第 \(i\) 个点的度为 \(c_i\),那么

\[Ans = \sum_{i=1}^{k}max(1,\frac {c_i}{2})-1 \]

第二问就是将度数为奇数的点任意配对连额外的边。

然后每个连通块跑欧拉回路,额外连的边会将回路割成若干段路径,这些路径之间以及连通块之间用1操作跳。

然后就是 \(\mathcal O(n + m)\)



#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x],y=edge[i].ver;i;i=edge[i].next,y=edge[i].ver)
namespace xin_io
{
	#define sb(x) cout<<#x" = "<<x<<' '
	#define jb(x) cout<<#x" = "<<x<<endl
	#define debug cout<<"debug"<<endl
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	char buf[1<<20],*p1 = buf,*p2 = buf; int ak; typedef long long ll; typedef unsigned long long ull;
	class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &s)
	{
		register int f = 0;s = 0; register char ch = gc();
		while(!isdigit(ch)) {f |= ch == '-'; ch = gc();}
		while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch  xor 48),ch = gc(); return s = f ? -s : s,*this;
	}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+7; const ll llinf = 1e18+7;
int n,m;
namespace xin
{
	class xin_edge{public:int next,ver,w;}edge[maxn];
	int head[maxn],rp = 1;
	inline void add(int x,int y,int z) {edge[++rp].ver = y;edge[rp].w = z; edge[rp].next = head[x]; head[x] = rp;}
	int ind[maxn];
	int num = 0,ret = 0,tot,c[maxn];
	bool vis[maxn];
	std::vector<int>vec[maxn];
	void dfs(int x)
	{
		vis[x] = 1;
		if(ind[x] & 1) ret ++,vec[tot].push_back(x),c[tot] ++;
		go(i,x)
			if(!vis[y])
			dfs(y);
	}
	int temp[maxn],top = 0;
	class xin_data
	{
		public:
			int op,to;
			xin_data(){}
			xin_data(int to,int op):op(op),to(to){}
	}ans[maxn],sta[maxn];
	int zhi = 0,jsq = 0;
	inline void oulalala()
	{
		sta[++zhi] = xin_data(vec[1][1],0);
		while(zhi)
		{
			int x = sta[zhi].to,i = head[x];
			while(i and vis[i]) i = edge[i].next;
			if(i)
			{
				sta[++zhi] = xin_data(edge[i].ver,edge[i].w);
				vis[i] = vis[i xor 1] = 1;
				head[x] = edge[i].next;
			}
			else
				ans[++jsq] = sta[zhi],--zhi;
		}
	}
	inline short main()
	{
		try(i,1,m)
		{	
			register int x,y; io >> x >> y;
			add(x,y,0); add(y,x,0);
			ind[x]++; ind[y]++;
		}
		try(i,1,n)
		if(!vis[i] and head[i])
		{
			ret = 0; tot ++;vec[tot].push_back(0);
			dfs(i);
			if(!c[tot]) vec[tot].push_back(i),vec[tot].push_back(i);
			num += std::max(c[tot]>>1,1);
		}
		try(i,3,c[1]) temp[++top] = vec[1][i];//,jb(vec[1][i]);
		try(i,2,tot)
		{
			add(vec[i][1],vec[i-1][2],1); add(vec[i-1][2],vec[i][1],1);
			try(j,3,c[i]) temp[++top] = vec[i][j];
		}
		for(register int i=2;i<=top;i+=2)
		{	
			add(temp[i],temp[i-1],1);
			add(temp[i-1],temp[i],1);
		}
		memset(vis,0,sizeof(vis));
		oulalala();
		cout<<num - 1<<endl;
		printf("%d\n",ans[jsq].to);
		throw(i,jsq-1,1)
			printf("%d %d\n",ans[i].op,ans[i].to);
		return 0;
	}
}
signed main()
{
	io >> n >> m;
	xin::main();
	return 0;
}

Lyk Love painting

似乎就是一个结论 \(dp\),忘了思路了。。。



#include<bits/stdc++.h>
using std::cout; using std::endl;
#define try(i,a,b) for(register signed i=a;i<=b;++i)
#define throw(i,a,b) for(register signed i=a;i>=b;--i)
#define go(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
	#define sb(x) cout<<#x" = "<<x<<' '
	#define jb(x) cout<<#x" = "<<x<<endl
	#define debug cout<<"debug"<<endl
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	char buf[1<<20],*p1 = buf,*p2 = buf; int ak; typedef long long ll; typedef unsigned long long ull;
	class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &s)
	{
		register int f = 0;s = 0; register char ch = gc();
		while(!isdigit(ch)) {f |= ch == '-'; ch = gc();}
		while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch  xor 48),ch = gc(); return s = f ? -s : s,*this;
	}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+7; const ll llinf = 1e18+7;
#define int long long
namespace xin
{
	int he1[maxn],he2[maxn],he3[maxn];
	int n,m,l,r;
	int f1[maxn],f2[maxn],f3[maxn];
	int dp[maxn];
	inline bool check(int x)
	{
		f1[0] = f2[0] = f3[0] = 0;
		try(i,1,n)
		{
			f1[i] = f1[i-1]; f2[i] = f2[i-1]; f3[i] = f3[i-1];
			while(he1[i] - he1[f1[i]] > x) f1[i] ++;
			while(he2[i] - he2[f2[i]] > x) f2[i] ++;
			while(he3[i] - he3[f3[i]] > x) f3[i] ++;
		}
		dp[0] = 0; try(i,1,n) dp[i] = m + 1;
		try(i,1,n)
		{
			dp[i] = std::min(dp[i],dp[f3[i]]+1);
			register int t1 = i,t2 = i,s = 0;
			while(s + 1 <= m and (t1 or t2))
			{
				if(t1 > t2) t1 = f1[t1];
				else t2 = f2[t2];s ++;
				dp[i] = std::min(dp[i],dp[std::max(t1,t2)] + s);
			}
			if(dp[i] > m) return 0;
		}
		return 1;
	}
	inline short main()
	{
		io >> n >> m;
		try(i,1,n) 
		{
			register int x; io >> x; r += x; l = std::max(l,x);
			he1[i] = he1[i-1] + x; he3[i] += x;
		}
		try(i,1,n)
		{
			register int x; io >> x; r += x; l = std::max(l,x);
			he2[i] = he2[i-1] + x; he3[i] += x;
		}
		try(i,1,n) he3[i] += he3[i-1];
		while(l != r - 1)
		{
			register int mid = l + r >> 1;
			if(check(mid)) r = mid;
			else l = mid;
		}
		if(check(l)) cout<<l<<endl;
		else cout<<r<<endl;
		return 0;
	}
}
signed main() {return xin::main();}
posted @ 2021-09-13 20:06  NP2Z  阅读(31)  评论(0编辑  收藏  举报