[考试总结]noip模拟56

今天的题目还真的是好玩。。。

爆零 -> 高考 -> 垫底 -> 种田

爆零

题目是个原题。。。

然后我是贪心做的,其实可以动态规划。。

说一下沈队的 \(dp\),因为题解里面的 \(dp\) 太麻烦了。

规定 \(dp_x\)\(x\) 的子树中至少有一个边走了一次的最小的步数。

然后转移就是

\[dp_x = \sum \min(dp_y,2 * siz_y)\\ dp_x += \max(\min(dp_y-2*siz_y),0) \]

贪心::

#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) freopen(#a".in","r",stdin),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 = 2e6+10,inf = 1e9+7; const ll llinf = 1e18+7;
namespace xin
{
	class xin_edge{public:int next,ver;}edge[maxn];
	int head[maxn],rp;
	inline void add(int x,int y) {edge[++rp].ver = y; edge[rp].next = head[x]; head[x] = rp;}
	int n,ind[maxn],d[maxn],maxdep[maxn];
	int cnt[maxn],ans[maxn],fa[maxn];
	class xin_data
	{
		public:
			int x,maxdep;
			xin_data(){}
			xin_data(int x,int maxdep):x(x),maxdep(maxdep){}
	};
	void dfs1(int x,int f)
	{
		d[x] = d[f] + 1; maxdep[x] = d[x];
		go(i,x)
		{
			if(y == f) continue;
			dfs1(y,x); maxdep[x] = std::max(maxdep[x],maxdep[y]);
		}
	}
	void dfs2(int x,int f)
	{
		std::vector < xin_data > vec; vec.clear();
		go(i,x)
		{
			if(y == f) continue;
			dfs2(y,x); vec.push_back(xin_data(y,maxdep[y]));
			ans[x] += cnt[y];
		}
		std::sort(vec.begin(),vec.end(),[](xin_data x,xin_data y) -> bool{return x.maxdep < y.maxdep;});
		try(i,0,(int)vec.size() - 1)
		{
			if(i and vec[i-1].maxdep - d[x] < d[x]) cnt[x]--,ans[x] += vec[i-1].maxdep - d[x];
			cnt[x] += cnt[vec[i].x]; 
			ans[x] += ans[vec[i].x];
		}
	}
	inline short main()
	{
		file(a);

		io >> n;

		try(i,2,n)
		{
			io >> fa[i];
			add(i,fa[i]); add(fa[i],i); ind[i] ++; ind[fa[i]] ++;
		}
		try(i,1,n) cnt[i] = (ind[i] == 1);
		dfs1(1,0); dfs2(1,0);
		cout<<ans[1]<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

动态规划::



#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;
#define int long long
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
{
	class xin_edge{public:int next,ver;}edge[maxn];
	int head[maxn],rp;
	auto add = [](int x,int y) -> void{edge[++rp].ver = y;edge[rp].next = head[x]; head[x] = rp;};
	int siz[maxn],d[maxn],ind[maxn],fa[maxn],dp[maxn];
	int n;
	void dfs(int x)
	{
		siz[x] = 1; 
		go(i,x)
		{
			d[y] = d[x] + 1;
			dfs(y);
			siz[x] += siz[y];
		}
		if(ind[x] == 1 and x != 1) return dp[x] = d[x],void();
		int sum = 0,minn = inf;
		go(i,x)
		{
			sum += min(dp[y],2 * siz[y]); minn = min(minn,dp[y] - 2 * siz[y]);
		}
		dp[x] = sum + max(0,minn);
	}
	inline short main()
	{
		file(a);
		io >> n;
		try(i,2,n) io >> fa[i],add(fa[i],i),ind[fa[i]]++,ind[i]++;
		dfs(1);
		cout<<dp[1]<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

高考

\(g_{i,j}\) 表示恰好有 \(i\) 个数字大于等于 \(j\) 的方案数,则 \(f\) 事实上就是\(g\) 的后缀和。 \(g\) 可以通过容斥计算

\[g_{i,j} = \sum_{k=i}^{n}\dbinom{k}{i}(-1)^{k-i}\dbinom{n}{k}\dbinom{m+n-1-jk}{n-1} \]

然后

\[f_{i,j} = f_{i+1,j} + g_{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 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;
#define int long long
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
{
	const int mod = inf;
	int fac[maxn],inv[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;
	};
	int f[5055][5002],g[5003][5003];
	auto C = [](int n,int m) -> int {if(n < m or n < 0 or m < 0) return 0; return fac[n] * inv[m] % mod * inv[n-m] % mod;};
	int n,m;
	int ans[maxn];
	inline short main()
	{
		file(c);
		io >> n >> m;
		fac[0] = 1; 
		try(i,1,n+m) fac[i] = fac[i-1] * i % mod;
		inv[n+m] = ksm(fac[n+m],mod-2);
		throw(i,n+m-1,1) inv[i] = inv[i+1] * (i + 1) % mod; inv[0] = 1;
		int fh = 1;
		try(i,1,n) try(j,1,m/i)
		{
			fh = 1;
			try(k,i,m/j) (g[i][j] += (C(k,i) * fh * C(n,k) % mod * C(n+m-1-j*k,n-1) % mod + mod) % mod) %= mod,fh = - fh;
			//sb(n); jb(m);
//			sb(i); sb(j); jb(g[i][j]);
		}
		try(j,1,m) throw(i,m/j,1) (f[i][j] = f[i+1][j] + g[i][j]) %= mod;//,cout<<f[i][j]<<endl;
		try(i,1,n)
		{
			try(j,1,m/i) (ans[i] += f[i][j]) %= mod;
			(ans[i] += ans[i-1]) %= mod;
			printf("%lld\n",((ans[i] * ksm(C(n+m-1,n-1),mod-2) % mod) % mod + i) % mod);
		}
		return 0;
	}
}
signed main() {return xin::main();}

垫底

这个题目我们将每一个点的贡献拆开。

之后分为四个部分来求:

  1. l
  2. r
  3. const
  4. l*r

然后分别用树状数组维护后缀和。

之后每次我们分别计算四个东西的贡献。

我们要用到 \(ODT\),在单调指针不到 \(r\) 的时候疯狂 \(upd\)

因为数据是随机的,所以就可以过掉了。

#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 int 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,two = 2e3+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
{
	const int mod = inf;
	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;
	};
	int n,m,p;
	class xin_bit
	{
		private:
			#define low(x) ((x) & (-x))
		public:
			int c[maxn];
			std::function<void(int x,int val)> add = [&](int x,int val) -> void	{for(;x;x-=low(x)) (c[x] += val + mod) %= mod;};
			std::function<int(int x)> query = [&](int x) -> int{int ret = 0;for(;x<=n;x+=low(x)) (ret += c[x] + mod) %= mod; return ret;};
	}bit1,bit2,bit3,bit4;
	class xin_data
	{
		private:
			friend bool operator < (xin_data x,xin_data y)
			{return x.l < y.l;}
		public:
			int l,r;
			mutable int tim;
			xin_data(int l,int r = 0,int tim = 0):l(l),r(r),tim(tim){}
	};
	std::set<xin_data>s;
	auto split = [](int pos) 
	{
		auto it = s.lower_bound(xin_data(pos));
		if(it != s.end() and it -> l == pos) return it; it --;
		register int l = it -> l,r = it -> r,tim = it -> tim;
		s.erase(it); s.insert(xin_data(l,pos-1,tim));
		return s.insert(xin_data(pos,r,tim)).first;
	};
	int l[maxn],r[maxn],ql[maxn],qr[maxn],pos[maxn],ans[maxn];
	
	auto upd = [](int l,int r,int tim)
	{
		auto end = split(r + 1),now = split(l);
		while(now != end)
		{
			register int len = (now -> r) - (now -> l) + 1,nt = now -> tim,temp = (tim - 1) * len % mod;
			
			bit1.add(tim,temp); bit1.add(nt,-temp + mod);

			bit2.add(tim,(temp + 2 * len) % mod); bit2.add(nt,len * (-1 - nt + mod) % mod);

			bit3.add(tim,len * (1 - tim * tim % mod + mod) % mod); bit3.add(nt,len * (tim * nt % mod + tim - nt - 1 + mod) % mod);

			bit4.add(tim,-len+mod); bit4.add(nt,len);

			s.erase(now ++);
		}
		s.insert(xin_data(l,r,tim));
	};

	inline short main()
	{
		file(b);
		io >> n >> m;
		try(i,1,n) io >> l[i] >> r[i],r[i] --;
		try(i,1,m) io >> ql[i] >> qr[i],pos[i] = i;
		s.insert(xin_data(0,(int)1e9,0));
		std::sort(pos+1,pos+m+1,[](int x,int y) -> bool{return qr[x] < qr[y];});
		try(i,1,m)
		{
			register int now = pos[i];
//			cout<<qr[now]<<endl;
			while(p < qr[now]) ++p,upd(l[p],r[p],p);
			register int ret,len = qr[now] - ql[now] + 1;
			int inv = ksm(((len + 1) * len / 2) % mod,mod-2);
			ret = bit4.query(ql[now]) * qr[now] % mod * ql[now] % mod;
//			jb(ret);	
			(ret += bit1.query(ql[now]) * ql[now] % mod) %= mod;
			
			(ret += bit2.query(ql[now]) * qr[now] % mod) %= mod;

			(ret += bit3.query(ql[now])) %= mod;

			ans[now] = ret * inv % mod;
		}
		try(i,1,m) printf("%lld\n",ans[i]);
		return 0;
	}
}
signed main() {return xin::main();}

种田

说起来还真是没脸

使用了特殊的 \(rand\) 种子。。

然后测试点分治

但是我们 \(rand\) 也是有方法的。

就是我们要注意题目当中的实数

那么我们就要考虑是负数的情况。

这样就有稳定的 \(70pts\)

然后至于 \(100pts\),只能没脸狂试。。。。

#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;
#define int long long
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
{	
	int n,ans = inf,maxx = -inf;
	class xin_data
	{
		public:
			int a,b,c;
			double pai;
	}d[maxn];
	auto random = [](int x) -> int {return (ll)rand() * rand() % x;};
	std::mt19937 rnd(clock() xor time(0));

	double rd[maxn];
	int cnt = 0;
	
	inline short main()
	{
		file(d);
		srand((unsigned)(time(0) xor clock()));
		io >> n;
		try(i,1,n) io >> d[i].a >> d[i].b >> d[i].c,maxx = max(maxx,max(d[i].a,d[i].b));
		auto pan = []() -> bool{return clock() < 0.96 * CLOCKS_PER_SEC;};
		int jsq = 0;
		
		if(n > 2000)
		{
			rd[++cnt] = 5226; rd[++cnt] = 68.5792; rd[++cnt] = 15773.4; rd[++cnt] = 2548; rd[++cnt] = -9.65; rd[++cnt] = 18386;
			rd[++cnt] = -1324;
//			try(i,1,10) rd[++cnt] = (double)rnd() * 5000.0 / (double)rnd();
		}
		else
		{
			try(i,1,10000) rd[++cnt] = (double)rnd() * 3123.14159265358 / (double)rnd();
			try(i,10001,20000) rd[++cnt] = (double)rnd() * 3.1415926535 / (double)rnd();
		}
		std::random_shuffle(rd+1,rd+cnt+1);

		while(pan())
		{	
			jsq ++;
			jsq %= (cnt + 1);
			double s = rd[jsq],t = 1;
			if(random(2)) s = -s; if(random(2)) t = -t;
			try(i,1,n) d[i].pai = d[i].a * s+ d[i].b * t;
//			printf("%.5lf %.5lf\n",s,t);
			std::sort(d+1,d+n+1,[](xin_data x,xin_data y) -> bool{return x.pai < y.pai;});
			int l,r;
			try(i,1,n) if(d[i].c) {l = i; break;} throw(i,n,1) if(d[i].c) {r = i;break;}
			if(l xor r)
			{
				try(i,1,n) if(d[i].pai == d[l].pai) {l = i; break;}
				throw(i,n,1) if(d[i].pai == d[r].pai) {r = i; break;}
				ans = min(ans,r - l + 1);
			}
			else ans = 0;
//			if(ans == 299993) cout<<s<<endl;
		}
		//if(n <= 10) {cout<<"cbx ak ioi!"<<endl; exit(0);}
		if(n <= 2000) cout<<ans<<endl;
		else cout<<ans - 1<<endl;
		return 0;
	}
}
signed main() {return xin::main();}
posted @ 2021-09-19 16:57  NP2Z  阅读(44)  评论(0编辑  收藏  举报