[考试总结]noip模拟37

然后今天暴力还是没有打满。。。。。。

考场心态复原:

第一题:这不就是一个扩展欧几里的嘛,简单。。
然后疯狂开始码,然后就过了样例,并且过了大样例。
之后继续看第二题,好像是个原题,然后发现不是,然后开第三题。
之后分析一波,发现中转边,然后只用一下子push进去几个起点就行,
然后也是一发大样例。
之后看第四题:
“怎么说也有200了,水个暴力就行了。。。”
然后。。。。
第四题抱零。。。。

还是不能掉以轻心。。。

数列

扩展欧几里的求不定方程。

对于形如 \(a*x_0 + b*y_0 = n\) 的不定方程为了求解 \(x_0\)\(y_0\),可以通过扩展欧几里得先求出满足 \(a*x + b*y = gcd(a, b)\)\(x\)\(y\) 。容易得到,若 \(gcd(a, b)|(x-y)((x-y)%gcd(a,b)==0)\) ,则该不定方程有整数解,否则无符合条件的整数解。得到 \(x\)\(y\) 后,可以通过 \(x_0 = x*n / gcd(a, b)\) 这个 \(x_0\) 相当关键,求出 \(x_0\).

然后就行了。。。



#include<bits/stdc++.h>
using std::cout; using std::endl;
#define int long long
#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 sb(x) cout<<#x" = "<<x<<' '
	#define jb(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 x,y;
	inline int abs(int x) {return x < 0 ? -x : x;}
	int exgcd(int a,int b)
	{
		int ret,temp;
		if( b == 0)	{x = 1; y = 0;return a;}
		int d = exgcd(b,a%b);
		temp = x;x = y; y = temp - a/b * y;
		return d;
	}
	inline int get_y(int a,int b,int x,int he){return (he - a * x) / b;}
	int ans = 0;
	int n,a,b,c[maxn];
	inline short main()
	{
		io >> n >> a >> b;
		a = abs(a); b = abs(b);
		if(a > b) std::swap(a,b);
		int gcd = exgcd(a,b);
		a /= gcd; b /= gcd;
		try(i,1,n) 
		{
			io >> c[i],c[i] = abs(c[i]);
			if(c[i] % gcd) {puts("-1"); exit(0);}
			c[i] /= gcd;
		}
		try(i,1,n)
		{
			register int k = c[i] % b;
			int zhuanx = x * k; int zhuany = y * k + (c[i] / b);
//			cout<<zhuanx<<' '<<zhuany<<endl;
			register int temp = abs(zhuanx) + abs(zhuany);
			if(zhuanx > 0)
			{
				int zhuan = abs(zhuanx) / b;
				zhuanx -= zhuan * b; zhuany += zhuan * a;
				temp = std::min(temp,abs(zhuanx) + abs(zhuany));
				temp = std::min(temp,abs(zhuanx-b) + abs(zhuany+a));
			}
			else if(zhuanx < 0)
			{
				int zhuan = abs(zhuanx) / b;
				zhuanx += zhuan * b; zhuany -= zhuan * a;
				temp = std::min(temp,abs(zhuanx) + abs(zhuany));
				temp = std::min(temp,abs(zhuanx+b) + abs(zhuany-a));
			}
			ans += temp;
		}
		cout<<ans<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

数对

状态转移方程:

\(f_{i,j}\) 表示前 \(i\) 个,然后最大的 \(a_i\)\(j\) 的最大权值和。

\[f_{i,j} = max_{j=1}^{min(d[i].a,d[i].b)} {f_{i-1,j}+d[i].w}\\ f_{i,j} = max_{j=d[i].a+1}^{d[i].b} = f_{i-1,j}+d[i].w \]

然后注意数组就有 \(60pts\)

然后发现其实线段树可以维护,之后愉快 \(AC\)

\(60pts\)



#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 sb(x) cout<<#x" = "<<x<<' '
	#define jb(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 = 3e3+10,inf = 1e9+7; const ll llinf = 1e18+7;
namespace xin
{
	class xin_seg
	{
		private:
			#define ls(fa) (fa << 1)
			#define rs(fa) (fa << 1 | 1)
			inline void up(int fa){t[fa].s = std::max(t[ls(fa)].s ,t[rs(fa)].s);}
			inline void down(int fa)
			{
				if(!t[fa].debt) return;
				t[ls(fa)].s += t[fa].debt ; t[rs(fa)].s += t[fa].debt;
				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*1000];
			void update(int fa,int l,int r,int ql,int qr,int val)
			{
				if(ql <= l and qr >= r) {t[fa].s += val; t[fa].debt += val; return ;}
				register int mid = l + r >> 1;
				down(fa);
				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);
			}
			void modify(int fa,int l,int r,int pos,int val)
			{
				if(l == r) {t[fa].s = std::max(val,t[fa].s); return;}
				register int mid = l + r >> 1;
				down(fa);
				if(pos <= mid) modify(ls(fa),l,mid,pos,val);
				else modify(rs(fa),mid+1,r,pos,val);
				up(fa);
			}
			int query(int fa,int l,int r,int ql,int qr)
			{
				if(ql <= l and qr >= r) return t[fa].s;
				register int mid = l + r >> 1,ret = 0;
				down(fa);
				if(ql <= mid) ret = std::max(ret,query(ls(fa),l,mid,ql,qr));
				if(qr >  mid) ret = std::max(ret,query(rs(fa),mid+1,r,ql,qr));
				return ret;
			}
	}t;
	class xin_data
	{
		private:
			friend bool operator < (xin_data x,xin_data y)
			{return (x.a + x.b) < (y.a + y.b);}
		public:	
			int a,b,w;
	}d[maxn];
	int n;
	int lisan[maxn * 1000],cnt = 0;
	int f[maxn][maxn + 3000];
	inline short main()
	{
		io >> n;
		try(i,1,n) 
		{
			io >> d[i].a >> d[i].b >> d[i].w;
			lisan[++cnt] = d[i].a; lisan[++cnt] = d[i].b;
		}
		std::sort(lisan+1,lisan+cnt+1);
		int k = std::unique(lisan+1,lisan+cnt+1) - (lisan + 1);
		try(i,1,n)
		{
			d[i].a = std::lower_bound(lisan+1,lisan+k+1,d[i].a) - lisan;
			d[i].b = std::lower_bound(lisan+1,lisan+k+1,d[i].b) - lisan;
		}
		std::sort(d+1,d+n+1);
		int ans = -inf;
		try(i,1,n)
		{
//			try(j,1,k) f[i][j] = f[i-1][j];
			int temp = t.query(1,1,k,1,std::min(d[i].a,d[i].b)) + d[i].w;
			t.modify(1,1,k,d[i].a,temp);
			if(d[i].a + 1 <= d[i].b)
				t.update(1,1,k,d[i].a+1,d[i].b,d[i].w);
//			try(j,1,std::min(d[i].a,d[i].b)) f[i][d[i].a] = std::max(f[i-1][j] + d[i].w,f[i][d[i].a]);
//			try(j,d[i].a+1,d[i].b) f[i][j] = f[i-1][j] + d[i].w;
		}
//		try(i,1,n){try(j,1,k) cout<<f[i][j]<<' '; cout<<endl;}
		cout<<t.t[1].s<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

\(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 asm(i,x) for(register signed i=head[x];i;i=edge[i].next)
namespace xin_io
{
	#define debug cout<<"debug"<<endl
	#define sb(x) cout<<#x" = "<<x<<' '
	#define jb(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 = 1e6+10,inf = 1e9+7; const ll llinf = 1e18+7;
namespace xin
{
	class xin_seg
	{
		private:
			#define ls(fa) (fa << 1)
			#define rs(fa) (fa << 1 | 1)
			inline void up(int fa){t[fa].s = std::max(t[ls(fa)].s ,t[rs(fa)].s);}
			inline void down(int fa)
			{
				if(!t[fa].debt) return;
				t[ls(fa)].s += t[fa].debt ; t[rs(fa)].s += t[fa].debt;
				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];
			void update(int fa,int l,int r,int ql,int qr,int val)
			{
				if(ql <= l and qr >= r) {t[fa].s += val; t[fa].debt += val; return ;}
				register int mid = l + r >> 1;
				down(fa);
				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);
			}
			void modify(int fa,int l,int r,int pos,int val)
			{
				if(l == r) {t[fa].s = std::max(val,t[fa].s); return;}
				register int mid = l + r >> 1;
				down(fa);
				if(pos <= mid) modify(ls(fa),l,mid,pos,val);
				else modify(rs(fa),mid+1,r,pos,val);
				up(fa);
			}
			int query(int fa,int l,int r,int ql,int qr)
			{
				if(ql <= l and qr >= r) return t[fa].s;
				register int mid = l + r >> 1,ret = 0;
				down(fa);
				if(ql <= mid) ret = std::max(ret,query(ls(fa),l,mid,ql,qr));
				if(qr >  mid) ret = std::max(ret,query(rs(fa),mid+1,r,ql,qr));
				return ret;
			}
	}t;
	class xin_data
	{
		private:
			friend bool operator < (xin_data x,xin_data y)
			{return (x.a + x.b) < (y.a + y.b);}
		public:	
			int a,b,w;
	}d[maxn];
	int n;
	int lisan[maxn],cnt = 0;
	inline short main()
	{
		io >> n;
		try(i,1,n) 
		{
			io >> d[i].a >> d[i].b >> d[i].w;
			lisan[++cnt] = d[i].a; lisan[++cnt] = d[i].b;
		}
		std::sort(lisan+1,lisan+cnt+1);
		int k = std::unique(lisan+1,lisan+cnt+1) - (lisan + 1);
		try(i,1,n)
		{
			d[i].a = std::lower_bound(lisan+1,lisan+k+1,d[i].a) - lisan;
			d[i].b = std::lower_bound(lisan+1,lisan+k+1,d[i].b) - lisan;
		}
		std::sort(d+1,d+n+1);
		int ans = -inf;
		try(i,1,n)
		{
//			try(j,1,k) f[i][j] = f[i-1][j];
			int temp = t.query(1,1,k,1,std::min(d[i].a,d[i].b)) + d[i].w;
			t.modify(1,1,k,d[i].a,temp);
			if(d[i].a + 1 <= d[i].b)
				t.update(1,1,k,d[i].a+1,d[i].b,d[i].w);
//			try(j,1,std::min(d[i].a,d[i].b)) f[i][d[i].a] = std::max(f[i-1][j] + d[i].w,f[i][d[i].a]);
//			try(j,d[i].a+1,d[i].b) f[i][j] = f[i-1][j] + d[i].w;
		}
//		try(i,1,n){try(j,1,k) cout<<f[i][j]<<' '; cout<<endl;}
		cout<<t.t[1].s<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

最小距离

考场上 \(\color{green} {AC}\) 的一个题目。

就是我们魔改一下 \(dijkstra\) 然后就可以求出每个非特殊点到特殊点的最近距离。

之后我们还需要记录一下是哪个转移的。

之后枚举每一个边之后统计答案。



#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 sb(x) cout<<#x" = "<<x<<' '
	#define jb(x) cout<<#x" = "<<x<<endl
	#define gc() p1 == p2 and (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? EOF : *p1++
	#define scanf ak = scanf
	char buf[1<<20],*p1 = buf,*p2 = buf; int ak; typedef long long ll; typedef unsigned int 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;
#define int long long
namespace xin
{
	#define mp std::make_pair
	class xin_edge{public:int next,ver,w;}edge[maxn];
	int head[maxn],zhi = 1;
	inline void add(int x,int y,int w) {edge[++zhi].ver = y; edge[zhi].w = w; edge[zhi].next = head[x]; head[x] = zhi;}
	std::priority_queue<std::pair<int,int>,std::vector<std::pair<int,int> >,std::greater<std::pair<int,int> > >q;
	int dis[maxn],spe[maxn],nre[maxn],ans[maxn];
	bool vis[maxn];
	int n,m,p;
	void dij()
	{
		while(!q.empty())
		{
			register int x = q.top().second; q.pop();
			if(vis[x]) continue; vis[x] = 1;
			asm(i,x) 
			{
				register int y = edge[i].ver,z = edge[i].w;
				if(dis[y] > dis[x] + z)
				{
					dis[y] = dis[x] + z; nre[y] = nre[x];
					q.push(mp(dis[y],y));
				}
			}
		}
		memset(ans,0x3f,sizeof(int) * (n + 1));
		for(register int i=2;i<=zhi;++i,++i)
		{
			register int y1 = edge[i].ver,y2 = edge[i xor 1].ver;
			register int n1 = nre[y1],n2 = nre[y2];
			if(n1 xor n2)
			{
				register int zhuan = dis[y1] + dis[y2] + edge[i].w;
				ans[n1] = std::min(ans[n1],zhuan); ans[n2] = std::min(ans[n2],zhuan);
			}
		}
	}
	inline short main()
	{
		io >> n >> m >> p;
		memset(dis,0x3f,sizeof(int) * (n + 1));
//		cout<<dis[1]<<endl;
		try(i,1,p) 
		{
			io >> spe[i];
			dis[spe[i]] = 0; q.push(mp(dis[spe[i]],spe[i]));nre[spe[i]] = spe[i];
		}
		try(i,1,m)
		{
			register int x,y,z; io >> x >> y >> z;
			add(x,y,z); add(y,x,z);
		}
		dij();
//		try(i,1,n) cout<<nre[i]<<' ';cout<<endl;
//		try(i,1,n) sb(dis[i]); cout<<endl;
		try(i,1,p) printf("%lld ",ans[spe[i]]);
		return 0;
	}
}
signed main() {return xin::main();}

真相

说简单就是一个大模拟,然而还是很有思维含量的。。

就是如果我们定下来第一个点的真假,那么从地一个人到接下来的一个 '$' 之间就都是可以确定的了。

之后我们就可以尝试枚举每一个这样的相连通的块,之后就可以 \(\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 sb(x) cout<<#x" = "<<x<<' '
	#define jb(x) cout<<#x" = "<<x<<endl
	#define scanf ak = scanf
	int ak;
}
using namespace xin_io; static const int maxn = 1e5+10,inf = 1e9+7; 
namespace xin
{
	class xin_data
	{
		public:
			char s[2];
			int num;
	}d[maxn];
	int n,T;
	int num[maxn][2],f[maxn][2],zhi,ton[maxn];
	std::vector<int>vec;
	inline short main()
	{
		scanf("%d",&T);
		while(T--)
		{
			zhi = 0;
			vec.clear();
			scanf("%d",&n);
			try(i,1,n)
			{
				scanf("%s",d[i].s);
				if(d[i].s[0] == '$') vec.push_back(i),scanf("%d",&d[i].num);
			}
			if(!vec.size())
			{
				register bool now = 1;
				try(i,1,n) if(d[i].s[0] == '-') now ^= 1;
				puts(now ? "consistent" : "inconsistent");
				continue;
			}
			int sum = 0;
			try(i,0,vec.size()-1)
			{
				register int pos = (vec[i]+1),next,now = 1,cnt = 0,tot = 1;
				if(pos > n) pos -= n;
				if(i == vec.size() - 1) next = vec[0];
				else next = vec[i+1];
				for(register int j=pos;j!=next;)
				{
					if(now) cnt++;
					if(d[j].s[0] == '-') now ^= 1;
					tot ++; j ++; if(j > n) j -= n;
				}
				ton[++zhi] = d[next].num;
				if(now)
				{
					cnt++;
					num[zhi][0] = cnt; num[zhi][1] = tot - cnt;
				}
				else
				{
					num[zhi][0] = tot - cnt;
					num[zhi][1] = cnt;
				}
				f[ton[zhi]][0] += num[zhi][0]; f[ton[zhi]][1] += num[zhi][1];
				sum += num[zhi][1];
			}
			bool ans = 0;
			try(i,0,n)
			{
				int cnt = f[i][0] - f[i][1] + sum;
				if(cnt == i) {ans = 1;break;}
			}
			puts(ans ? "consistent" : "inconsistent");
			try(i,1,zhi) f[ton[i]][0] = f[ton[i]][1] = 0;
		}
		return 0;
	}
}
signed main() {return xin::main();}
posted @ 2021-08-12 21:05  NP2Z  阅读(37)  评论(0编辑  收藏  举报