noip37

为何我对T3情有独钟

T1

不难发现,题目要求的就是 \(ax+by=c\) ,已知 \(a,b,c\) ,求 \(\min\{|a|+|b|\}\) ,那就用扩欧求一组特解,再分情况讨论即可。

Code
#include<cstdio>
#define MAX 100010
#define re register
#define int long long
namespace OMA
{
	struct stream
	{
		template<typename type>inline stream &operator >>(type &s)
		{
			int w=1; s=0; char ch=getchar();
			while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
			while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
			return s*=w,*this;
		}
	}cin;
	inline int exgcd(int a,int b,int &x,int &y)
	{
		if(!b)
		{ x = 1,y = 0; return a; }
		int d = exgcd(b,a%b,x,y);
		int z = x; x = y; y = z-y*(a/b);
		return d;
	}
	inline int min(int a,int b)
	{ return a<b?a:b; }
	inline int abs(int a)
	{ return a>=0?a:-a; }
	int n,a,b,x[MAX],ans;
	signed main()
	{
		cin >> n >> a >> b;
		if(a>b)
		{ int t=a; a=b; b=t; }
		int xi,yi;
		int gcd = exgcd(a,b,xi,yi);
		a /= gcd,b/= gcd;
		for(re int i=1; i<=n; i++)
		{
			cin >> x[i];
			if(x[i]%gcd)
			{ printf("-1\n"); return 0; }
		}
		for(re int i=1,x1,y1,k; i<=n; i++)
		{
			x1 = xi*x[i]/gcd,y1 = yi*x[i]/gcd,k = abs(x1/b);
			if(x1>=0&&y1<=0)
			{ ans += min(abs(x1-k*b)+abs(y1+k*a),abs(x1-(k+1)*b)+abs(y1+(k+1)*a)); }
			else if(x1<=0&&y1>=0)
			{ ans += min(abs(x1+k*b)+abs(y1-k*a),abs(x1+(k+1)*b)+abs(y1-(k+1)*a)); }
		}
		printf("%lld\n",ans);
		return 0;
	}
}
signed main()
{ return OMA::main(); }

T2

考场上一眼看上去像队长快跑,然而带权。

但其实如果那道题真的明白了,这道也不算难。

然而我...

首先写出基础dp,设 \(dp_{i,j}\) 表示当前选到了第 \(i\) 个数对,其中,所选的数对中最大的 \(a\)\(j\),则可以列出转移方程:

  1. \(i\) 后,最大值不是 \(a_{i}\) ,则,

\[dp_{i,j} = \max\{dp_{i-1,j}\}+w_{i}\;,j\in[a_{i},b_{i}] \]

  1. \(i\) 后,最大值为 \(a_{i}\) ,则,

\[dp_{i,a_{i}} = \max\{dp_{i-1,j}\}+w_{i}\;,j\in[1,\min(a_{i},b_{i})] \]

  1. 不选,直接由上层转移,则,

\[dp_{i,j}=\max\{dp_{i-1,j}\}\;,j\in[1,max] \]

列出来后,直接转移,时空双爆,60pts。

观察式子,发现可以用线段树来维护,1操作对应区间修改,2操作对应单点修改,3操作不用管,会直接覆盖。

复杂度 \(O(n\log n)\)

附基础dp

Code
#include<cstdio>
#include<algorithm>
#define MAX 100010
#define re register
#define int long long
using std::sort;
using std::unique;
using std::lower_bound;
namespace OMA
{
	int n,cnt;
	int tmp[MAX<<1];
	int dp[6010][6010];
	struct node
	{
		int a,b,w;
		inline friend bool operator <(const node &a,const node &b)
		{ return a.a+a.b<b.a+b.b; }
	}p[MAX];
	inline int max(int a,int b)
	{ return a>b?a:b; }
	inline int min(int a,int b)
	{ return a<b?a:b; }
	struct Segment_Tree
	{
		struct TREE
		{
			int l,r;
			int val;
			int lazy;
		}st[MAX<<3];
		inline int ls(int p)
		{ return p<<1; }
		inline int rs(int p)
		{ return p<<1|1; }
		inline void Push_up(int p)
		{ st[p].val = max(st[ls(p)].val,st[rs(p)].val); }
		inline void Push_down(int p)
		{
			if(st[p].lazy)
			{
				st[ls(p)].val += st[p].lazy;
				st[ls(p)].lazy += st[p].lazy;
				st[rs(p)].val += st[p].lazy;
				st[rs(p)].lazy += st[p].lazy;
				st[p].lazy = 0;
			}
		}
		inline void build(int p,int l,int r)
		{
			st[p].l = l,st[p].r = r;
			if(l==r)
			{ return ; }
			int mid = (l+r)>>1;
			build(ls(p),l,mid),build(rs(p),mid+1,r);
		}
		inline void update1(int p,int l,int r,int val)
		{
			if(l>r)
			{ return ; }
			if(l<=st[p].l&&st[p].r<=r)
			{ st[p].val += val,st[p].lazy += val; return ; }
			Push_down(p);
			int mid = (st[p].l+st[p].r)>>1;
			if(l<=mid)
			{ update1(ls(p),l,r,val); }
			if(r>mid)
			{ update1(rs(p),l,r,val); }
			Push_up(p);
		}
		inline void update2(int p,int pos,int val)
		{
			if(st[p].l==st[p].r)
			{ st[p].val = max(st[p].val,val); return ; }
			Push_down(p);
			int mid = (st[p].l+st[p].r)>>1;
			if(pos<=mid)
			{ update2(ls(p),pos,val); }
			else
			{ update2(rs(p),pos,val); }
			Push_up(p);
		}
		inline int query(int p,int l,int r)
		{
			if(l<=st[p].l&&st[p].r<=r)
			{ return st[p].val; }
			Push_down(p);
			int res = -1,mid = (st[p].l+st[p].r)>>1;
			if(l<=mid)
			{ res = max(res,query(ls(p),l,r)); }
			if(r>mid)
			{ res = max(res,query(rs(p),l,r)); }
			return res;
		}
	}Tree;
	struct stream
	{
		template<typename type>inline stream &operator >>(type &s)
		{
			int w=1; s=0; char ch=getchar();
			while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
			while(ch>='0'&&ch<='9'){ s = s*10+ch-'0'; ch=getchar(); }
			return s*=w,*this;
		}
	}cin;
	signed main()
	{
		//freopen("node.in","r",stdin);
		cin >> n;
		for(re int i=1,a,b,w; i<=n; i++)
		{
			p[i] = (node){(cin >> a,a),(cin >> b,b),(cin >> w,w)};
			tmp[++cnt] = a,tmp[++cnt] = b;
		}
		sort(p+1,p+1+n);
		sort(tmp+1,tmp+1+cnt);
		cnt = unique(tmp+1,tmp+1+cnt)-tmp-1;
		for(re int i=1; i<=n; i++)
		{
			p[i].a = lower_bound(tmp+1,tmp+1+cnt,p[i].a)-tmp;
			p[i].b = lower_bound(tmp+1,tmp+1+cnt,p[i].b)-tmp;
			//printf("%lld %lld\n",p[i].a,p[i].b);
		}
		Tree.build(1,1,cnt);
		for(re int i=1; i<=n; i++)
		{
			int tmp = Tree.query(1,1,min(p[i].a,p[i].b));
			Tree.update1(1,p[i].a,p[i].b,p[i].w);
			Tree.update2(1,p[i].a,p[i].w+tmp);
		}
		printf("%lld\n",Tree.st[1].val);
		/*int ans = 0;
		for(re int i=1; i<=n; i++)
		{
			for(re int j=1; j<=n*2; j++)
			{ dp[i][j] = dp[i-1][j]; }
			for(re int j=p[i].a; j<=p[i].b; j++)
			{ dp[i][j] = max(dp[i][j],dp[i-1][j]+p[i].w); }
			for(re int j=1; j<=min(p[i].a,p[i].b); j++)
			{ dp[i][p[i].a] = max(dp[i][p[i].a],dp[i-1][j]+p[i].w); }
		}
		for(re int i=1; i<=n; i++)
		{
			for(re int j=1; j<=n*2; j++)
			{ ans = max(ans,dp[i][j]); }
			//printf("\n");
		}
		printf("%lld\n",ans);*/
		return 0;
	}
}
signed main()
{ return OMA::main(); }

T3

\(p\) 遍最短路,10pts。

正解:

跑个多源最短路,啥是多源最短路,就是有多个源点,在 \(dij\) 一开始往队列压点的操作时,把源点都压到里边,也就是本题的特殊点,再开个 \(pre\) 数组记录下每个点是由哪个源点扩展过来的,其他都是 \(dij\) 常规操作。

跑完一遍最短路,得到的是某个源点到当前点所构成的最短路径,具体是那个源点,则记录在了 \(pre\) 数组里。

对于答案,我们枚举每一条边,对于边的两个端点,如果其是由两个不同的源点扩展过来的,则可以得到当前两个源点通过 \(\{u,v\}\) 连接的距离 \(dis_{u}+dis_{v}+w\) 。 枚举取最小值即可。

画个图可能更好理解。

Code
#include<queue>
#include<cstdio>
#include<climits>
#include<cstring>
#include<algorithm>
#define MAX 200020
#define re register
#define int long long
#define INF 1145141919810
using std::sort;
using std::priority_queue;
int n,m,p;
int x[MAX];
int ans[MAX];
struct graph
{
	int from;
	int next;
	int to;
	int w;
}edge[MAX<<1];
int cnt=1,head[MAX];
inline void add(int u,int v,int w)
{ edge[++cnt] = (graph){u,head[u],v,w},head[u] = cnt; }
namespace MSSP
{
	struct my
	{
		int dis,id;
		inline friend bool operator <(const my &a,const my &b)
		{ return a.dis>b.dis; }
	};
	priority_queue<my>q;
	bool vis[MAX];
	int dis[MAX],pre[MAX];
	inline void dijkstra()
	{
		memset(dis,0x3f,sizeof(dis));
		for(re int i=1; i<=p; i++)
		{ q.push((my){dis[x[i]] = 0,pre[x[i]] = x[i]}); }
		while(!q.empty())
		{
			int u = q.top().id; q.pop();
			if(vis[u])
			{ continue ; }
			vis[u] = 1;
			for(re int i=head[u],v,w; i; i=edge[i].next)
			{
				v = edge[i].to,w = edge[i].w;
				if(dis[v]>dis[u]+w)
				{
					pre[v] = pre[u];
					dis[v] = dis[u]+w;
					q.push((my){dis[v],v});
				}
			}
		}
	}
}using namespace MSSP;
namespace OMA
{
	struct stream
	{
		template<typename type>inline stream &operator >>(type &s)
		{
			int w=1; s=0; char ch=getchar();
			while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
			while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
			return s*=w,*this;
		}
	}cin;
	inline int min(int a,int b)
	{ return a<b?a:b; }
	signed main()
	{
		//freopen("node.in","r",stdin);
		//freopen("my.out","w"i,stdout);
		cin >> n >> m >> p;
		for(re int i=1; i<=p; i++)
		{ cin >> x[i]; ans[x[i]] = INF; }
		for(re int i=1,u,v,w; i<=m; i++)
		{
			cin >> u >> v >> w;
			add(u,v,w),add(v,u,w);
		}
		dijkstra();
		for(re int i=2,u,v,w; i<=cnt; i+=2)
		{
			u = edge[i].from,v = edge[i].to,w = edge[i].w;
			if(pre[u]!=pre[v])
			{
				ans[pre[u]] = min(ans[pre[u]],dis[u]+dis[v]+w);
				ans[pre[v]] = min(ans[pre[v]],dis[u]+dis[v]+w);
			}
		}
		for(re int i=1; i<=p; i++)
		{ printf("%lld\n",ans[x[i]]); }
		return 0;
	}
}
signed main()
{ return OMA::main(); }

T4

比较sb的模拟

Solution

image

Code
#include<cstdio>
#define MAX 100010
#define re register
namespace OMA
{
	int t,n,top,sta[MAX];
	int opt[MAX],cnt[MAX],sum,cot;
	int rec[MAX],a[MAX][2],b[MAX][2];
	signed main()
	{
		scanf("%d",&t);
		while(t--)
		{
			scanf("%d",&n);
			sum = cot = top = 0;
			for(re int i=1; i<=n; i++)
			{
				char s[5];
				scanf("%s",s);
				if(s[0]=='$')
				{ opt[i] = 1; scanf("%d",&cnt[i]); sta[++top] = i; }
				if(s[0]=='+')
				{ opt[i] = 2; }
				if(s[0]=='-')
				{ opt[i] = 3; }
			}
			if(!top)
			{
				int jud = 1;
				for(re int i=1; i<=n; i++)
				{ if(opt[i]==3){ jud ^= 1; } }
				if(jud)
				{ printf("consistent\n"); }
				else
				{ printf("inconsistent\n"); }
				continue ; 
			}
			for(re int i=1; i<=top; i++)
			{
				int fr = sta[i]+1,be,tot = 1,truth = 0,jud = 1;
				if(i==top)
				{ be = sta[1]; }
				else
				{ be = sta[i+1]; }
				if(fr>n)
				{ fr -= n; }
				for(re int j=fr; j!=be; )
				{
					if(jud)
					{ truth++; }
					if(opt[j]==3)
					{ jud ^= 1; }
					j++,tot++;
					if(j>n)
					{ j -= n; }
				}
				rec[++cot] = cnt[be];
				if(jud)
				{
					truth++;
					a[cot][0] = tot-truth;
					a[cot][1] = truth;
				}
				else
				{
					a[cot][0] = truth;
					a[cot][1] = tot-truth;
				}
				b[rec[cot]][0] += a[cot][0];
				b[rec[cot]][1] += a[cot][1];
				sum += a[cot][0];
			}
			bool flag = false;
			for(re int i=0; i<=n; i++)
			{ if(sum-b[i][0]+b[i][1]==i){ flag = true; break ; } }
			if(flag)
			{ printf("consistent\n"); }
			else
			{ printf("inconsistent\n"); }
			for(re int i=0; i<=n; i++)
			{ a[i][0] = a[i][1] = b[i][0] = b[i][1] = 0; }
		}
		return 0;
	}
}
signed main()
{ return OMA::main(); }

posted @ 2021-08-13 06:28  -OMA-  阅读(69)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end