[考试总结]noip模拟30

二维 XIN 队算法打挂。。。

然后只剩下完蛋的 \(15pts\)。。。

然后 \(T2\) 莽了一个 \(\mathcal O(n!)\) 的完蛋全排列。。

然后 \(20pts\)

然而 \(T3\) 救我于水火之中。。。

本来对着 \(40pts\) 的部分分数,然后奇迹 \(A\) 掉。。

发现其实常数极小。。。

开心。。。

毛一琛

这到题目就是之前一直也说过的 \(meet\;in\;middle\) 优化 XIN 算法。

不会的可以看

然后我们就会对复杂度开根。

就是 \(\mathcal O(3^{\frac{n}{2}})\)

飞快。

其实可以跑将近 \(40\) 的数据。

有童鞋可能对复杂度有疑问。

实际上就是对于每一种数字有 \(3\) 中状态: 不选,在第一集合,在第二集合

然后就没了。。



#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 asm(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
	#define enum(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; int ak; typedef long long ll; typedef unsigned long long ull;
	class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &x)
	{
		register type s = 0; register int f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch  xor 48),ch = gc(); return x = s * f,*this;
	}}io;
}
using namespace xin_io; static const int maxn = (1 << 20) + 1,inf = 1e9+7,mod = 998244353; const ll llinf = 1e18+7;
namespace xin
{
	int w[maxn],n,ans = 0,tot;
//	int a;
	std::unordered_map<int,int>mp;
	std::vector<int>vec[maxn];
	bool vis[maxn];
	int mid;
	void dfs1(int now,int rmb1,int rmb2,int a)
	{
		if(now == mid + 1)
		{
			int temp = abs(rmb1 - rmb2);
			if(!mp[temp]) mp[temp] = ++tot;
			int zhuan = mp[temp]; 
			vec[zhuan].push_back(a);
			return ;
		}
		dfs1(now+1,rmb1,rmb2,a); 
		dfs1(now+1,rmb1+w[now],rmb2,a | (1 << (now - 1)));
		dfs1(now+1,rmb1,rmb2+w[now],a | (1 << (now - 1)));
	}
	void dfs2(int now,int rmb1,int rmb2,int a)
	{
		if(now == n + 1)
		{
			int temp = abs(rmb1 - rmb2);
			if(!mp[temp]) return ;
			int zhuan = mp[temp];
			try(i,0,vec[zhuan].size() - 1)
				vis[(a << mid) |  vec[zhuan][i]] = 1;
			return ;
		}
		dfs2(now+1,rmb1,rmb2,a);
		dfs2(now+1,rmb1+w[now],rmb2,a | (1 << ((now - mid) - 1)));
		dfs2(now+1,rmb1,rmb2+w[now],a | (1 << ((now - mid) - 1)));
	}
	inline short main()
	{
		io >> n; try(i,1,n) io >> w[i];//,enum(w[i]);
		mid = n >> 1; 
		dfs1(1,0,0,0); dfs2(mid+1,0,0,0);
		try(i,0,(1 << n)-1)
			ans += vis[i];
		cout<<ans-1<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

毛二琛

这个题目还是比较难的的。

我考场上的暴力还是朴素的 \(next_permutation\),然后 \(\mathcal O(n!)\) 复杂度。

然后拿到场均的 \(20pts\) 高分。。

正解是 \(dp\)

我们用一个 \(zhuan\) 数组来记录这个数字要转移到的位置。

之后 \(f_{i,j}\) 转移答案。



#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 asm(i,x) for(register signed i=head[x];i;i=edge[i].next)
#define int long long
namespace xin_io
{
	#define enum(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; int ak; typedef long long ll; typedef unsigned long long ull;
	class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &x)
	{
		register type s = 0; register int f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch  xor 48),ch = gc(); return x = s * f,*this;
	}}io;
}
using namespace xin_io; static const int maxn = 5e3+10,inf = 1e9+7,mod = 1e9+7; const ll llinf = 1e18+7;
namespace xin
{
	int zhuan[maxn],a[maxn];
	int n,ans;
	int g[maxn][maxn],f[maxn][maxn];
	inline short main()
	{
		io >> n;
		try(i,0,n-1) io >> a[i];
		try(i,0,n-1)
			if(i < a[i]) zhuan[i-1] = 1,zhuan[a[i] - 1] = 1;
			else try(j,a[i],i-2) zhuan[j] = 1;
		f[0][1] = g[0][1] = 1;
		try(i,1,n-2) try(j,1,i+1)
		{
			if(zhuan[i-1]) (f[i][j] += g[i-1][i] - g[i-1][j-1] + mod) %= mod;
			else (f[i][j] += g[i-1][j-1]) %= mod;
			(g[i][j] = g[i][j-1] + f[i][j]) %= mod;
		}
		try(i,0,n-1) (ans += f[n-2][i]) %= mod;
		cout<<ans % mod<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

毛三琛

这个题目实际上就是我们想的 \(\mathcal O(n^2logn)\) 的复杂度就能过的题目。

你可能不信,我也不信,然而就是过了。。



#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 asm(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
	#define enum(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; int ak; typedef long long ll; typedef unsigned long long ull;
	class xin_stream{public:template<typename type>inline xin_stream &operator >> (type &x)
	{
		register type s = 0; register int f = 1; register char ch = gc();
		while(!isdigit(ch)) {if(ch == '-') f = -1; ch = gc();}
		while( isdigit(ch)) s = (s << 1) + (s << 3) + (ch  xor 48),ch = gc(); return x = s * f,*this;
	}}io;
}
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+7;const ll llinf = 1e18+7;
namespace xin
{
	int n,mod,k;
	int a[maxn],b[maxn];
	int ans = inf;
	inline bool check(int x)
	{
		register int res = 0,sum = 0;
		try(i,1,n)
		{
			if(b[i] > x)return false;
			if(res + b[i] > x) res=0,sum++;
			res += b[i];
		}
		return sum < k;
	}
	int p[maxn];
	inline short main()
	{
		srand(unsigned(time(0)) xor clock());
		io >> n >> mod >> k;
		try(i,1,n) io >> a[i],p[i] = i;
		std::random_shuffle(p+1,p+n+1);
		try(i,0,mod-1)
		{
			register int l=0,r=0,res = inf,temp;
			try(j,1,n)
			{
				b[j] = (a[j] + p[i]) % mod;
				r += b[j];
			}
			if(!check(ans)) continue;
			while(l <= r)
			{
				register int mid = l + r >> 1;
				if(check(mid)) res=mid,r=mid-1;
				else l = mid+1;
			}
			ans = std::min(ans,res);
		}
		cout<<ans<<endl;
		return 0;
	}
}
signed main() {return xin::main();}
posted @ 2021-08-04 21:28  NP2Z  阅读(50)  评论(0编辑  收藏  举报