[考试总结]noip模拟34

实际上简单的题目并不能被题目所吓到,仔细分析实际上难度并不是很高。

如果存在显然的部分分数,其实特盘一下也比较好,有可能你的程序就卡在这个地方。。

这次暴力打的不是很挂,\(T1\) 也还是差一个 \(nth\)_\(element\) ,二分答案的思路显然,但是要有两个 \(log_2\)

\(T2\) 没有进行仔细的分析,实际上手动推导发现可以推导成为一个形式,并且与深度的奇偶性有关。

\(T3\) 这个属实大神题,需要使用常熟优秀的树状数组。

Merchant

我们首先进行二分答案,二分时间,然后进行统计 \(check\),但是发现如果在 \(check\)中使用 \(sort\),就会 \(TLE\)\(78pts\) ,因为这时的复杂度是 \(nlog^2\)

然后我们其实可以发现,我们并不需要让他有序,我们只需要将前 \(m\) 大小的提到一边。

这时 \(nth_element\) 的作用就体现出来了,之后我们就可以 \(\mathcal O(n)\) 排除顺序,之后加和比较。



#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 debug cout<<"debug"<<endl
	#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;
}
#define int long long
using namespace xin_io; static const int maxn = 2e6+10,inf = 1e9+7,mod = 998244353; const ll llinf = 1e18+7;
namespace xin
{
	class xin_data
	{
		public:
			int k,b;
			xin_data(){}
			xin_data(int k,int b):k(k),b(b){}
			inline int val(int t) {return k * t + b;}
	}d[maxn];
	int n,m,s,temp;
	int a[maxn];
	inline bool comp(int x,int y) {return x > y;}
	inline bool check(int x)
	{
		try(i,1,n) a[i] = d[i].val(x);
		std::nth_element(a+1,a+(n-m),a+n+1);
		s = temp;
		throw(i,n,n-m+1)
		{
			if(a[i] < 0) continue;
			s -= a[i];
			if(s <= 0) return true;
		}
		return false;
	}
	inline short main()
	{
		io >> n >> m >> s; temp = s;
		try(i,1,n)	io >> d[i].k >> d[i].b;
		register int l = 0,r = inf,mid;
		if(check(0)) {cout<<0<<endl; return 0;}
		while(l != r - 1 and l < r)
		{
			mid = l + r >> 1;
			if(check(mid)) r = mid;
			else l = mid;
		}
		if(check(l)) cout<<l<<endl;
		else if(check(mid)) cout<<mid<<endl;
		else cout<<r<<endl;
//		cout<<sizeof(a) / (1 << 20)<<" MB"<<endl;
		return 0;	
	}
}
signed main() {return xin::main();}

Equation

我们进行推导,发现每一个式子都可以推成

\[x_1=k+x_u \]

或者

\[x_1=k-x_u \]

这个符号取决与深度的奇偶性。

然后我们强制使树的边权正负交错,也就是 \(sum_y=w_y-sum_x\)

然后对于 \(2\) 操作,在线段树上维护即可。



#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 debug cout<<"debug"<<endl
	#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,mod = 998244353; const ll llinf = 1e18+7;
#define int long long
namespace xin
{
	class xin_edge{public:int w,next,ver;}edge[maxn];
	int head[maxn],zhi = 0;
	inline void add(int x,int y,int z) {edge[++zhi].ver = y; edge[zhi].w = z; edge[zhi].next = head[x]; head[x] = zhi;}
	class xin_seg
	{
		private:
			#define ls(fa) (fa << 1)
			#define rs(fa) (fa << 1 | 1)
			inline void up(int fa) {t[fa].s = t[ls(fa)].s + t[rs(fa)].s;}
			inline void down(int fa,int l,int r)
			{
				if(!t[fa].debt) return ;
				register int mid = l + r >> 1;
				t[ls(fa)].s += t[fa].debt * (mid - l + 1); t[rs(fa)].s += t[fa].debt * (r - mid);
				t[ls(fa)].debt += t[fa].debt; t[rs(fa)].debt += t[fa].debt;
				t[fa].debt = 0;
			}
		public:
			class xin_tree{public:int s,debt;}t[maxn * 4];
			void update(int fa,int l,int r,int ql,int qr,int val)
			{
				if(ql <= l and qr >= r) return t[fa].s += (r - l + 1) * val,t[fa].debt += val,void();
				register int mid = l + r >> 1;
				down(fa,l,r);
				if(ql <= mid) update(ls(fa),l,mid,ql,qr,val);
				if(qr >  mid) update(rs(fa),mid+1,r,ql,qr,val);
				up(fa);
			}
			int query(int fa,int l,int r,int pos)
			{
				if(l == r) return t[fa].s;
				register int mid = l + r >> 1,ret = 0; down(fa,l,r);
				if(pos <= mid) ret += query(ls(fa),l,mid,pos); 
				else ret += query(rs(fa),mid+1,r,pos);
				return ret;
			}
	}t;


	int n,qnum,fa[maxn];
	int in[maxn],out[maxn],tot = 0,d[maxn],sum[maxn],w[maxn];
	void xt(int x)
	{
		in[x] = ++tot; d[x] = d[fa[x]] + 1;
		asm(i,x)
		{
			register int y = edge[i].ver;
			sum[y] = w[y] - sum[x];
			xt(y);
		}
		out[x] = tot;
	}
	inline short main()
	{
		io >> n >> qnum;
		try(i,2,n)
		{
			io >> fa[i] >> w[i];
			add(fa[i],i,w[i]);
		}
		xt(1);
		try(i,1,qnum)
		{
			register int op; io >> op;
			if(op & 1)
			{
				register int x,y,z; io >> x >> y >> z;
				register int p1 = t.query(1,1,n,in[x]),p2 = t.query(1,1,n,in[y]);
				if(!(d[x] & 1)) p1 = -p1; if(!(d[y] & 1)) p2 = -p2;
				register int ret1 = sum[x] + p1,ret2 = sum[y] + p2;
				if((d[x] & 1) and (d[y] & 1)) 
				{
					if((z - ret1 - ret2) & 1) puts("none");
					else printf("%lld\n",(z - ret1 - ret2) >> 1);
				}
				else if(!(d[x] & 1) and !(d[y] & 1))
				{
					if((ret1 + ret2 - z) & 1) puts("none");
					else printf("%lld\n",(ret1 + ret2 - z) >> 1);
				}
				else
				{
					if(ret1 + ret2 == z) puts("inf");
					else puts("none");
				}
			}
			else
			{
				register int x,z; io >> x >> z;
				register int p = z - w[x];
				w[x] = z;
				if(!(d[x] & 1)) p = -p;
				t.update(1,1,n,in[x],out[x],p);
			}
		}
		return 0;
	}
}
signed main() {return xin::main();}

Rectangle

首先第一思路就是拿四个线卡来卡去。

然后就是 \(n^4\)

可以拿二十多分。。

正解实际上是先拿两条线。

之后发现答案贡献与两条线之间的 \(y\) 有关,所以用树状数组来维护 \(\sum y\)

#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 debug cout<<"debug"<<endl
	#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 = 2500+10,inf = 1e9+7,mod = 1e9+7; const ll llinf = 1e18+7;
namespace xin
{
	#define int long long
	int n;
	class xin_bit
	{
		private:
			#define lowbit(x) (x & -x)
		public:
			int c[2][maxn][maxn];
			inline void plus(int id,int k,int x,int val)
			{
				for(int i=x;i<=2500;i+=lowbit(i))
					c[id][k][i] += val;
			}
			inline int query(int id,int k,int x)
			{
				register int ret = 0;
				for(int i=x;i;i-=lowbit(i)) ret += c[id][k][i];
				return ret;
			}
	}bit;
	int a[maxn][maxn],ans;
	bool vis[maxn][maxn];
	inline short main()
	{
		io >> n;
		try(i,1,n)
		{
			register int x,y; io >> x >> y;
			a[x][++a[x][0]] = y; 
		}
		try(i,1,2500)
		{
			std::sort(a[i]+1,a[i]+a[i][0]+1);
			a[i][a[i][0]+1] = 2501;
		}
		try(i,1,2500)
		{
			if(!a[i][0]) continue;
			try(j,1,a[i][0])
			if(!vis[i][a[i][j]])
			{
				vis[i][a[i][j]] = 1;
				bit.plus(1,i,a[i][j],1);
				bit.plus(0,i,a[i][j],a[i][j]);
			}
			throw(j,i-1,1)
			{
				if(!a[j][0]) continue;
				register int l1 = 1,l2 = 1;
				try(k,1,a[j][0])
					if(!vis[i][a[j][k]])
					{
						vis[i][a[j][k]] = 1;
						bit.plus(1,i,a[j][k],1);
						bit.plus(0,i,a[j][k],a[j][k]);
					}
				register int temp = std::max(a[i][1],a[j][1]);
				while(a[i][l1+1] <= temp) l1 ++; while(a[j][l2+1]<=temp) l2 ++;
				while(l1 <= a[i][0] and l2 <= a[j][0])
				{
					register int zhuan = std::min(a[i][l1+1],a[j][l2+1]);
					int ret1 = (bit.query(0,i,zhuan-1)-bit.query(0,i,temp-1));
					int ret2 = (bit.query(1,i,zhuan-1)-bit.query(1,i,temp-1));
					//enum(ret1); enum(ret2);
					ans=(ans+(i-j)*(ret1*bit.query(1,i,std::min(a[i][l1],a[j][l2]))-(ret2*bit.query(0,i,std::min(a[i][l1],a[j][l2])))))%mod;
					temp = zhuan;
					if(a[i][l1+1] <= temp) l1 ++; if(a[j][l2+1] <= temp) l2 ++;
				}
			}
		}
		cout<<ans<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

[考试总结]noip模拟34

上一篇:jQuery基础


下一篇:Jquery获取前一个元素和后一个元素的方法,JavaScript和Jquery中判断一个元素是否存在