noip35

T1

考场乱搞出锅了...

正解:

把原序列按k往左和往右看成两个序列,求个前缀和,找下一个更新的位置,直接暴跳。

Code
#include<cstdio>
#include<cstring>
#define MAX 100100
#define re register
#define int long long
namespace OMA
{
	int t,n,k;
	int c[MAX],a[MAX],b[MAX];
	int sum[MAX][2],next[MAX][2];
	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()
	{
		cin >> t;
		while(t--)
		{
			memset(next,0,sizeof(next));
			cin >> n >> k;
			for(re int i=1; i<=n; i++)
			{ cin >> c[i]; }
			int len1 = 1,len2 = 1;
			a[1] = b[1] = 0;
			for(re int i=k; i>=2; i--)
			{ a[++len1] = c[i]; }
			for(re int i=k+1; i<=n; i++)
			{ b[++len2] = c[i]; }
			for(re int i=1; i<=len1; i++)
			{ sum[i][0] = sum[i-1][0]+a[i]; }
			for(re int i=1; i<=len2; i++)
			{ sum[i][1] = sum[i-1][1]+b[i]; }
			int nim = sum[1][0],pos = 1;
			for(re int i=2; i<=len1; i++)
			{ if(sum[i][0]<nim){ nim = sum[i][0],next[pos][0] = i,pos = i; } }
			nim = sum[len1][0],pos = len1;
			for(re int i=len1-1; i>=1; i--)
			{ if(sum[i][0]<nim){ nim = sum[i][0],next[pos][0] = i,pos = i; } }
			nim = sum[1][1],pos = 1;
			for(re int i=2; i<=len2; i++)
			{ if(sum[i][1]<nim){ nim = sum[i][1],next[pos][1] = i,pos = i; } }
			nim = sum[len2][1],pos = len2;
			for(re int i=len2-1; i>=1; i--)
			{ if(sum[i][1]<nim){ nim = sum[i][1],next[pos][1] = i,pos = i; } }
			if(sum[len1][0]+sum[len2][1]>0)
			{ printf("No\n"); continue ; }
			int l = 1,r = 1;
			bool flag = true;
			while(next[l][0]||next[r][1])
			{
				flag = !next[l][0]?false:true;
				for(re int i=l+1; i<=next[l][0]; i++)
				{
					if(sum[i][0]+sum[r][1]>0)
					{ flag = false; break ; }
				}
				if(!flag)
				{
					flag = !next[r][1]?false:true;
					for(re int i=r+1; i<=next[r][1]; i++)
					{
						if(sum[i][1]+sum[l][0]>0)
						{ flag = false; break ; }
					}
					if(!flag)
					{ break ; }
					r = next[r][1];
					continue ;
				}
				l = next[l][0];
			}
			if(!flag)
			{ printf("No\n"); continue ; }
			l = len1,r = len2; flag = true;
			while(next[l][0]||next[r][1])
			{
				flag = !next[l][0]?false:true;
				for(re int i=l-1; i>=next[l][0]; i--)
				{
					if(sum[i][0]+sum[r][1]>0)
					{ flag = false; break ; }
				}
				if(!flag)
				{
					flag = !next[r][1]?false:true;
					for(re int i=r-1; i>=next[r][1]; i--)
					{
						if(sum[i][1]+sum[l][0]>0)
						{ flag = false; break ; }
					}
					if(!flag)
					{ break ; }
					r = next[r][1];
					continue ;
				}
				l = next[l][0];
			}
			if(!flag)
			{ printf("No\n"); }
			else
			{ printf("Yes\n"); }
		}
		return 0;
	}
}
signed main()
{ return OMA::main(); }

T2

\(next\_permutation\)+\(2^{n-1}\) 50pts。

正解:

不会...

T3

直接跑两遍最短路,20pts。

乱搞:

显然刚刚的做法是假的,画个图就知道。

考虑如何让它不那么假,我们可以枚举 \(i,i\in[2,n-1]\) ,先删去 \(i\) ,即将其值赋成0,然后再正反跑两遍最短路,如果两遍最短路中都经过了当前的 \(i\) ,说明 \(i\) 是我必须要加上的点,再把当前的答案加上 \(i\) 的值即可。

最后再跑两遍不删点的最短路,比较一下答案即可。

然而好像也是假的

Code
//应该是假做法,数据太水了
#include<queue>
#include<cstdio>
#include<cstring>
#define MAX 62500
#define re register
using std::queue;
const int N = 255;
int n,m,p1[N],p2[N];
struct graph
{
	int next;
	int to;
}edge[MAX];
int cnt=1,head[N];
inline void add(int u,int v)
{ edge[++cnt] = (graph){head[u],v},head[u] = cnt; }
namespace SSSP
{
	bool vis[MAX];
	int dis[MAX],pre[MAX];
	inline void spfa(int u)
	{
		memset(dis,0x3f,sizeof(dis));
		memset(pre,0,sizeof(pre));
		memset(vis,0,sizeof(vis));
		queue<int>q; q.push(u);
		dis[u] = p2[u]; vis[u] = true;
		while(!q.empty())
		{
			int v = q.front(); q.pop();
			vis[v] = false;
			for(re int i=head[v],k; i; i=edge[i].next)
			{
				k = edge[i].to;
				if(dis[k]>dis[v]+p2[k])
				{
					dis[k] = dis[v]+p2[k];
					pre[k] = v;
					if(!vis[k])
					{ q.push(k); vis[k] = true; }
				}
			}
		}
	}
}using namespace SSSP;
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()
	{
		cin >> n >> m;
		for(re int i=1; i<=n; i++)
		{ cin >> p1[i]; }
		for(re int i=1,u,v; i<=m; i++)
		{ cin >> u >> v; add(u,v); }
		int ans = MAX;
		for(re int i=2; i<=n-1; i++)
		{
			int tmp = 0;
			for(re int j=1; j<=n; j++)
			{ p2[j] = p1[j]; }
			p2[i] = 0;
			spfa(1);
			tmp += dis[n];
			int u = n;
			bool flag = true,jud = false;
			while(pre[u])
			{ if(pre[u]==i){ flag = false; } p2[u] = 0; u = pre[u]; }
			p2[1] = 0;
			spfa(n);
			while(pre[u])
			{ if(pre[u]==i&&!flag){ jud = true; tmp += p1[i]; } u = pre[u]; }
			tmp += dis[1];
			//ans = min(ans,tmp);
			if(jud)
			{ ans = min(ans,tmp); /*printf("ans=%d tmp=%d\n",ans,tmp);*/ }
		}
		int tmp = 0;
		for(re int i=1; i<=n; i++)
		{ p2[i] = p1[i]; }
		spfa(1);
		tmp += dis[n];
		int u = n;
		while(pre[u])
		{ p2[u] = 0; u = pre[u]; }
		p2[1] = 0;
		spfa(n);
		tmp += dis[1];
		ans = min(ans,tmp);
		printf("%d\n",ans>=MAX?-1:ans);
		return 0;
	}
}
signed main()
{ return OMA::main(); }

T4

不会...

posted @ 2021-08-10 21:19  -OMA-  阅读(111)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end