[考试总结]noip模拟55

×××× \(NOI\) 模拟赛

看到题目的时候,以为自己药丸。。。

Skip

抱着 \(NOI\) 第一题的心态打开了这个题目。

看了 \(5\) 分钟之后。。。。

似乎不难唉,我似乎只要推出来一个不是很难的基础 \(dp\) ,然后 \(max\) 用树状数组优化一下似乎就 \(Ac\) 了。

然后推出基础 \(dp\) 方程:

\[f_i = \max_{j=1}^{i-1} (f_j - calc(i,j)) + a_i\\ Ans = \max_{i=1}^{n}(f_i - calc(i,n+1)) \]

然后注意所有都跳过的情况,然后就有很多分数。

然而只有 \(30pts\),然后的数据范围就是 \(10^5\),但是 \(60\%\) 的数据保证随机。。。

这个有意义吗???答案是有的。

我们发现转移的时候取 \(\max\) 是去找的,那么既然数据随机,那么基本转移都会从一个较近的地方转移过来。

那么我们就将 \(j\) 的枚举顺序从 \(i-1\) 开始到 \(1\),然后发现 \(i-j \geq 3000\),那么我们就 \(break\)

之后就是 \(60\%\)

然后考虑正解。

是一个上凸包

式子挺好推导的,我就不推了,结果就是:

\[\frac{(f_j-\frac{j^2+j}{2})-(f_k-\frac{k^2-k}{2})}{j-k}>-i \]

记得一定是 \(-i\),在推导的过程中会将 \(k-j\) 挪过来,然后记得变号。

之后我们使用 \(cdq\) 分治来去除大小的限制,然后双指针就搞定了。。。



%: pragma GCC optimize(3)
#include<bits/stdc++.h>
using std::cout; using std::endl;
#define int long long
#define try(i,a,b) for(register int 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 file(a) FILE *FI = freopen(#a".in","r",stdin); FI = freopen(#a".out","w",stdout)
	#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;
auto max = [](int x,int y) -> int{return x > y ? x : y;}; auto min = [](int x,int y) -> int{return x < y ? x : y;};
namespace xin
{
	#define fn(x) ((x) * (x))
	class xin_data
	{
		public:
			int x,y,val,f;
	}d[maxn];
	int n,ans[maxn];
	int deque[maxn];

	auto scale(int x,int y) -> double{return (double)(d[y].y - d[x].y) / (double)(d[y].x - d[x].x);};

	void cdq(int l,int r)
	{
		register int mid = l + r >> 1;
		if(l == r) return; cdq(l,mid);
		std::sort(d + l,d+mid+1,[](xin_data x,xin_data y) ->bool{return x.x < y.x;});
		std::sort(d+mid+1,d+r+1,[](xin_data x,xin_data y) ->bool{return x.x < y.x;});
		register int p = l,front = 0,back = 1;
		try(i,mid+1,r)
		{
			while(p <= mid and d[p].x < d[i].x)
			{
				while(front > back and scale(deque[front-1],deque[front]) <= scale(deque[front],p)) front --;
//				jb(scale(deque[front-1],deque[front]));
				deque[++ front] = p ++;
			}
//			cout<<p<<' '<<front<<endl;
			while(front > back and scale(deque[back],deque[back+1]) >= -d[i].x) back ++;
//			cout<<back<<' '<<front<<endl;
			if(back > front) continue;
			ans[d[i].x] = d[i].f = max(d[i].f,d[deque[back]].y + d[i].val - (fn(d[i].x) - d[i].x) / 2 + d[i].x * d[deque[back]].x);
//			cout<<ans[d[i].x]<<endl;
			d[i].y = d[i].f - d[i].x * (d[i].x + 1) / 2;
		}
		std::sort(d+mid+1,d+r+1,[](xin_data x,xin_data y) -> bool{return x.val == y.val ? x.x < y.x : x.val < y.val;});
		cdq(mid+1,r);
	}

	inline short main()
	{
		file(skip);	
		auto calc = [](int l,int r) -> int
		{
			if(r - l == 1) return 0;
			register int len = r - l - 1;
			return (1 + len) * len >> 1;
		};
		io >> n;
		memset(ans,128,sizeof(int) * (n + 1)); 
		try(i,1,n)
		{
			io >> d[i].val;
			d[i].x = i; ans[i] = d[i].f = d[i].val - i * (i - 1) / 2;
			d[i].y = d[i].f - (fn(d[i].x) + d[i].x) / 2;
		}
		std::sort(d+1,d+n+1,[](xin_data x,xin_data y) -> bool{return x.val == y.val ? x.x < y.x : x.val < y.val;});
//		try(i,1,n) cout<<d[i].x<<' '<<d[i].y<<' '<<d[i].val<<' '<<d[i].f<<endl;
		cdq(1,n);
//		try(i,1,n) sb(i),jb(ans[i]);
		int maxx = ans[n];
		try(i,1,n-1) maxx = max(maxx,ans[i] - (n - i) * (n - i + 1) / 2);
		cout<<maxx<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

String

Permutation

就是:

\[\sum_{i=1}^{k}\dbinom{n-i}{k-i+2} + \sum_{i-2}^{n}(i-\dbinom{i-1}{2}-1)\dbinom{n-i-1}{k-2} \]



#include<bits/stdc++.h>
using std::cout; using std::endl;
#define int long long
#define try(i,a,b) for(register int 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
{
	auto max = [](int x,int y) -> int{return x > y ? x : y;}; auto min = [](int x,int y) -> int{return x < y ? x : y;};
	#define file(a) FILE *FI = freopen(#a".in","r",stdin); FI = freopen(#a".out","w",stdout)
	#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,k;
namespace shit
{
	const int mod = inf;
	int A[maxn][11],a[maxn],fac[maxn];
	int b[11],cnt = 0,zhi;
	void dfs(int ms)
	{
		if(zhi == ms)
		{
			++cnt;
			try(i,1,zhi) A[cnt][i] = a[i];
//			try(i,1,zhi) cout<<a[i]<<' '; cout<<endl;
			return ;
		}
		try(i,a[zhi]+1,n)
		{
			a[++zhi] = i;
			dfs(ms);
			zhi --;
		}
	}
	inline short main()
	{
		dfs(k);
		fac[0] = 1;
		try(i,1,n) fac[i] = fac[i-1] * i;
		int ans = 0;
		auto abs = [](int x) -> int{return x < 0 ? -x : x;};
		int tot = fac[n] / (fac[k] * (fac[n-k]));
		try(i,1,tot-1) (ans += abs(A[i][m] - A[i+1][m])) %= mod;
		cout<<ans<<endl;
		return 0;
	}
}
namespace xin
{
	const int mod = inf;
	int fac[maxn],inv[maxn],in[maxn];
	auto ksm(int x,int y,int ret = 1) -> int
	{
		while(y)
		{
			if(y & 1) ret = ret * x % mod;
			x = x * x % mod; y >>= 1;
		}
		return ret;
	};
	auto C = [](int n,int m) -> int
	{
		if(m < 0 or n < 0) return 0;
		if(n < m) return 0;
		return fac[n] * inv[m] % mod* inv[n-m] % mod;
	};
	inline short main()
	{	
		fac[0] = inv[0] = 1;
		try(i,1,n) fac[i] = fac[i-1] * 1ll * i % mod;
		inv[n] = ksm(fac[n],mod-2);
		throw(i,n-1,1) inv[i] = inv[i+1] * (i+1) % mod;
		
		n = n - k + m;k = m;

//		cout<<C(4,3)<<endl;
		int ans = 0;
		try(i,1,k) (ans += C(n-i,k-i+2)) %= mod;
		try(i,2,n) (ans += C(n-i-1,k-2) * (i - C(i-1,2) - 1 + mod) % mod) %= mod;
		cout<<ans<<endl;

		return 0;
	}
}
signed main()
{
	file(perm);
	io >> n >> k >> m;
	if(n <= 20) shit::main();
	else xin::main();
	return 0;
}

小P的生成树

这个东西发现并不能直接排序,那么我们呢所需要的就是这些东西正确大小关系。

如何正确起来呢?

就是我们发现在角度固定的时候那么模长也会固定。

那我们就可以开始枚举弧度,从 \(0\)\(2\pi\),之后每次进行一次最打生成树。

然后答案就是每次算出来的最大值。。

然后这个做法速度是正解的 \(1000\) 倍。。。。。。




%: pragma GCC optimize(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 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 file(a) FILE *FI = freopen(#a".in","r",stdin); FI = freopen(#a".out","w",stdout)
	#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
{
	const double pi = 3.14159265358979323846;
	class xin_data{public:int x,y,a,b;double pai;}d[maxn];
	int n,m,fa[maxn];
	inline int find(int x) {return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);}
	double ans = -inf * 1.0;
	inline short main()
	{
		file(mst);
		io >> n >> m;
		try(i,1,m) io >> d[i].x >> d[i].y >> d[i].a >> d[i].b;
		for(double deg = 0.0;deg <= pi * 2;deg += 0.06)
		{
			double si = std::sin(deg),co = std::cos(deg);
			try(i,1,n) fa[i] = i;
			try(i,1,m) d[i].pai = d[i].a * co + d[i].b * si;
			std::sort(d+1,d+m+1,[](xin_data x,xin_data y) -> bool{return x.pai > y.pai;});
			int jsq = 0,tota = 0,totb = 0;
			try(i,1,m)
			{
				register int fx = find(d[i].x),fy = find(d[i].y);
				if(fx == fy) continue;
				fa[fx] = fy; tota += d[i].a; totb += d[i].b;
				if(++jsq == n - 1) break;
			}
			ans = std::max(ans,std::sqrt(tota * tota + totb * totb));
		}
		printf("%.6lf\n",ans);
		return 0;
	}
}
signed main() {return xin::main();}
posted @ 2021-09-18 06:45  NP2Z  阅读(60)  评论(1编辑  收藏  举报