[考试总结]noip模拟43

这个题目出的还是很偷懒。。。。

第一题。。。第二题。。。第三题。。。四。。。。

好吧。。。

这几次考得都有些问题,似乎可能是有些疲惫,脑袋也是转不太动,考完总觉得自己是能力的问题,但是改一分钟之后会发现自己硬生生把正解干成了暴力。

第一题

这个题目一眼看上去是一个很不错的贪心题目。

之后我们确实可以使用贪心来做这个题目。

其实就是我们发现一定会是先走到小的里面,然后再去折到上面。

然后其实这个题目还是可以使用 \(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 asm(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;
namespace xin
{
	class xin_edge{public:int next,ver;}edge[maxn];
	int head[maxn],zhi = 0;
	inline void add(int x,int y) {edge[++zhi].ver = y; edge[zhi].next = head[x]; head[x] = zhi;}
	int n,ind[maxn];
	int d[maxn],maxd[maxn];
	int sum[maxn],val[maxn];
	class xin_data
	{
		private:
			friend bool operator < (xin_data x,xin_data y)
			{return x.maxd < y.maxd;}
		public:
			int x,maxd;
			xin_data(){}
			xin_data(int x,int maxd):x(x),maxd(maxd){}
	};
	void dfs1(int x,int f)
	{
		d[x] = d[f] + 1; maxd[x] = d[x];
		asm(i,x)
		{
			register int y = edge[i].ver;
			if(y == f) continue;
			dfs1(y,x);
			maxd[x] = std::max(maxd[x],maxd[y]);
		}
	}
	void dfs2(int x,int f)
	{
		std::vector < xin_data > vec; vec.clear();
		asm(i,x)
		{
			register int y = edge[i].ver;
			if(y == f) continue;
			dfs2(y,x);
			vec.push_back(xin_data(y,maxd[y]));
			val[x] += sum[y];
		}
		std::sort(vec.begin(),vec.end());
		try(i,0,(int)vec.size() - 1)
		{
			if(i and vec[i-1].maxd - d[x] < d[x]) sum[x]--,val[x] += vec[i-1].maxd - d[x];
			sum[x] += sum[vec[i].x]; val[x] += val[vec[i].x];
		}
	}
	inline short main()
	{
		io >> n;
		try(i,1,n-1)
		{
			register int x,y; io >> x >> y;
			add(x,y); add(y,x); ind[x] ++; ind[y] ++;
		}
		dfs1(1,0);
		try(i,1,n) if(ind[i] == 1) sum[i] = 1;
		dfs2(1,0);
		cout<<val[1]<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

第二题

似乎好像是用 \(dij\) 或者是 \(spfa\),但是我使用了 \(nb\) 方法过了。

我们有一个很 \(naive\) 的想法就是二分答案,之后每一个格子这样 \(\mathcal O(nm)\) 的去找,然后把小的那个加上需要的差值。

然后我们就很容易发现这个做法是个假的。

但是。

进行的每一次 \(\mathcal O(nm)\) 扫描,其实都是一次修正性算法。

所以每一次进行这个算法,都会更加正确。

所以我们只需要多做几次,也就是增加几个常数,然后就可以顺利过掉这个题目。

#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 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;
}
#define int long long
using namespace xin_io; static const int maxn = 1e6+10,inf = 1e9+7; const ll llinf = 1e18+7;
namespace xin
{
	#define abs(x) (x < 0 ? -x : x)
	int n,m,k;
	int a[maxn/200][maxn/200],b[maxn/200][maxn/200];
	inline bool check(int x)
	{
		register int temp = k;
		try(i,1,n) try(j,1,m) b[i][j] = a[i][j];
		try(cse,1,14)
		try(i,1,n) try(j,1,m)
		{
			if(j - 1 >= 1) //(i,j-1)
			{
				register int cha = b[i][j] - b[i][j-1];
				if(abs(cha) > x) 
				{
					temp -= abs(cha) - x;
					if(cha < 0) b[i][j] += abs(cha) - x;
					else b[i][j-1] += abs(cha) - x;
				}
			}
			if(j + 1 <= m) //(i,j+1)
			{
				register int cha = b[i][j] - b[i][j+1];
				if(abs(cha) > x)
				{
					temp -= abs(cha) - x;
					if(cha < 0) b[i][j] += abs(cha) - x;
					else b[i][j+1] += abs(cha) - x;
				}
			}
			if(i + 1 <= n and j - 1 >= 1) //(i+1,j-1)
			{
				register int cha = b[i][j] - b[i+1][j-1];
				if(abs(cha) > x)
				{	
					temp -= abs(cha) - x;
					if(cha < 0) b[i][j] += abs(cha) - x;
					else b[i+1][j-1] += abs(cha) - x;
				}
			}
			if(i - 1 >= 1) //(i-1,j)
			{
				register int cha = b[i][j] - b[i-1][j];
				if(abs(cha) > x)
				{
					temp -= abs(cha) - x;
					if(cha < 0) b[i][j] += abs(cha) - x;
					else b[i-1][j] += abs(cha) - x;
				}
			}
			if(i -1 >= 1 and j + 1 <= m) //(i-1,j+1)
			{
				register int cha = b[i][j] - b[i-1][j+1];
				if(abs(cha) > x)
				{
					temp -= abs(cha) - x;
					if(cha < 0) b[i][j] += abs(cha) - x;
					else b[i-1][j+1] += abs(cha) - x;
				}
			}
			if(i + 1 <= n) //(i+1,j)
			{
				register int cha = b[i][j] - b[i+1][j];
				if(abs(cha) > x)
				{
					temp -= abs(cha) - x;
					if(cha < 0) b[i][j] += abs(cha) - x;
					else b[i+1][j] += abs(cha) - x;
				}
			}
		}
		return temp >= 0;
	}
	int maxx = -inf;
	inline short main()
	{
		io >> n >> m >>k ;
		try(i,1,n) try(j,1,m) io >> a[i][j],maxx = std::max(a[i][j],maxx);
		register int l = 0,r = maxx;
		while(l != r - 1 and l < r)
		{
			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();}

第三题

一个 \(10\) 分暴力滚粗了。。。。

第四题

一个很强的 \(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 asm(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
{
	#define fmod(x) (x -= (x >= mod) ? mod : 0)
	int ans = 0;
	int f[maxn/300][maxn/300],g[maxn/300][maxn/300];
	int n,mod;
	int sum[maxn/300][maxn/300];
	inline short main()
	{
		io >> n >> mod; f[0][0] = 1;
		try(i,1,n) try(j,1,n) f[i][j] = (f[i-1][j-1] + f[i-1][j] * j % mod),fmod(f[i][j]);
		try(i,1,n) g[0][i] = 1;
		try(i,1,n) try(j,1,n) g[i][j] = (g[i-1][j+1] + g[i-1][j] * j % mod),fmod(g[i][j]);
		try(i,1,n) throw(j,n,1)
		{
			sum[i][j] = f[i-1][j] * (g[n-i][j] + 2 * (n - i * 1ll) * g[n-i-1][j] % mod) % mod;
			sum[i][j] += sum[i][j+1]; fmod(sum[i][j]);
		}
		try(x,1,n)
		{
			register int ans = 0;
			try(i,1,n)
			{
				register int temp = sum[i][x];
				(temp += f[i-1][x-1] * (g[n-i][x] + 2 * (n - i * 1ll) * g[n-i-1][x] % mod) % mod); fmod(temp);
				(ans += temp); fmod(ans);
			}
			printf("%lld ",ans);
		}
		return 0;
	}
}
signed main() {return xin::main();}

posted @ 2021-08-22 11:19  NP2Z  阅读(51)  评论(0编辑  收藏  举报