[考试总结]noip模拟53

ZYB和售货机

题目描述的很麻烦,说实话就是这个东西有依赖关系,然后构成一个图

然后我们每次找到连接每个点的最大值与次大值,之后我们沿着最大值去找环。

发现环之后我们是一定要去断开的。

这时候我们用次大值去替换一定是最优的。

所以就是了。

然后计算可以获得的最大收益。



#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 = 1e6+10,inf = 1e9+7;const ll llinf = 1e18+7;
namespace xin
{
	auto min = [](int x,int y) -> int {return x < y ? x : y;};
	ll ans;
	int n,num,minn;
	int fir[maxn],sec[maxn],a[maxn],c[maxn],f[maxn],d[maxn],val[maxn],vis[maxn];
	auto dfs = [](int x) -> void
	{
		while(1)
		{
			if(vis[x]) return ans -= (vis[x] == num) * minn,void();
			vis[x] = num ;if(!fir[x]) return ; 
			ans += 1ll * val[fir[x]] * a[x]; minn = min(minn,val[fir[x]] - val[sec[x]]);
			if(x xor fir[x]) x = fir[x]; else return;
		}
	};
	inline short main()
	{
		file(goods);
		;;;;;
		io >> n;
		try(i,1,n) io >> f[i] >> c[i] >> d[i] >> a[i];
		try(i,1,n)
		{
			val[i] = d[f[i]] - c[i];
			if(val[i] > val[fir[f[i]]]) sec[f[i]] = fir[f[i]],fir[f[i]] = i;
			else if(val[i] > val[sec[f[i]]]) sec[f[i]] = i;
		}
		try(i,1,n) if(!vis[i]) ++num,minn = inf,dfs(i);
		cout<<ans<<endl;
		return 0;
	}
}
signed main() {return xin::main();}

ZYB玩字符串

这个题目还是的解法比较新颖

我们这个的解法是用一个区间 \(dp\) 来判断其合法性。

复杂度自然是很高。

但是完全是跑不满的。

转移方程:

\[f_{i,j} |= f_{i,j-1} and\; [prefix_{(j-i) mod \;len+1} ] \\ f_{i,j} |= f_{i,j-k*len}\;and\;f_{j-k*len+1,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) 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 scanf ak = scanf
	#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 = 1e3+10,inf = 1e9+7;const ll llinf = 1e18+7;
namespace xin
{
	bool f[maxn][maxn];
	char s[maxn],prefix[maxn],ans[maxn],temp[maxn];
	int T,n;
	int yue[maxn];
	std::vector<char>vec;
	std::map<std::vector<char>,int>vis;


	auto check = [](int l,int r) -> bool
	{
		try(i,0,n) {memset(f[i],0,sizeof(int) * (n + 1));}
		try(i,l,r) prefix[i - l + 1] = s[i];
		try(i,1,n) if(s[i] == s[l]) f[i][i] = 1;
		int length = r - l + 1;
		try(len,1,n) try(i,1,n - len + 1)
		{
			register int j = i + len - 1;
			f[i][j] |= f[i][j-1] & (prefix[(j - i) % length + 1] == s[j]);
			for(register int k=1;k<=j/length;++k)
				f[i][j] |= f[i][j - k * length] & f[j-k*length+1][j];
		}
		return f[1][n];
	};


	auto comp = [](int len) -> bool
	{
		if(!strlen(ans)) return 1;
		try(i,1,len) if(temp[i] > ans[i]) return 1;
		return 0;
	};

	auto record = [](int l,int r) -> void
	{
		try(i,l,r) temp[i - l + 1] = s[i];
		if(comp(r - l + 1)) {try(i,1,r-l+1) ans[i] = temp[i];ans[r-l+2] = '\0';}
	};

	auto div = [](int x) -> void
	{
		int ms = std::sqrt(x); yue[0] = 0;
		try(i,1,ms) yue[++yue[0]] = i,yue[++yue[0]] = x / i;
		std::sort(yue+1,yue+yue[0]+1);
	};

	inline short main()
	{
		file(string);
		scanf("%d",&T);
		while(T--)
		{
			scanf("%s",s+1); n = strlen(s + 1); bool ok = 0;
//			jb(check(4,8));
			div(n); vis.clear();
			try(i,1,yue[0]) {int len = yue[i]; try(l,1,n - len + 1)
			{
				if(ok) break;
				register int r = l + len - 1;
				vec.clear();
				try(i,l,r) vec.push_back(s[i]);
				if(!vis[vec]) vis[vec] = 1;
				else continue;
				if(check(l,r)) {record(l,r); ok = 1;}
			}}
			printf("%s\n",ans+1);
		}
		return 0;
	}
}
signed main() {return xin::main();}

午餐

似乎挺像吵闹少年团的那个题目

那就是有限制的 \(dij\) 就行了呗。。。



%: pragma GCC optimize(3)
#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,b) freopen(#a"","r",stdin),freopen(#b"","w",stdout)
	#define sb(x) cout<<#x" = "<<x<<' '
	#define jb(x) cout<<#x" = "<<x<<endl
	#define debug cout<<"debug"<<endl
	#define scanf ak = scanf
	#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;
namespace xin
{
	#define mp std::make_pair
	class xin_edge{public:int next,ver,maxx,minn;}edge[maxn];
	class xin_data{public:int x,y,l,r;}d[maxn];
	int head[maxn],rp;
	auto add = [](int x,int y,int maxx,int minn) -> void{edge[++rp].ver = y ;edge[rp].maxx = maxx; edge[rp].minn = minn;edge[rp].next = head[x]; head[x] = rp;};
	auto max = [](int x,int y) -> int{return x > y ? x : y;}; auto min = [](int x,int y) -> int{return x < y ? x : y;};
	int n,m; std::queue < int > q;
	int tar[maxn],lim[maxn],dis[maxn]; bool vis[maxn];
	auto spfa = []() -> void
	{
		while(q.size()) 
		{
			register int x = q.front(); q.pop();
			go(i,x) {register int mx = edge[i].maxx,mn = edge[i].minn; if(lim[x] > mx and lim[y] <= mn) {lim[y] = mn + 1; if(!vis[y]) vis[y] = 1,q.push(y);}}
			vis[x] = 0;
		}
	};
	auto dijkstra = []() -> void
	{
		std::priority_queue<std::pair<int,int>,std::vector<std::pair<int,int> >,std::greater<std::pair<int,int> > > q;
		memset(vis,0,sizeof(bool) * (n + 1)); memset(dis,0x3f,sizeof(int) * (n + 1)); dis[1] = 0; q.push(mp(0,1));
		while(q.size())
		{
			register int x = q.top().second; q.pop(); vis[x] = 1;
			go(i,x) 
			{
				register int mx = edge[i].maxx,mn = edge[i].minn,temp = max(dis[x],max(lim[y],mn));
				if(temp < dis[y] and temp <= mx) dis[y] = temp,q.push(mp(dis[y],y));
			}
			while(q.size() and vis[q.top().second]) q.pop();
		}
	};
	inline short main()
	{
		file(lunch.in,lunch.out);
		io >> n >> m;
		try(i,1,m) io >> d[i].x >> d[i].y >> d[i].l >> d[i].r,add(d[i].x,d[i].y,d[i].r,d[i].l),add(d[i].y,d[i].x,d[i].r,d[i].l);
		try(i,1,n) {io >> tar[i]; if(!(~tar[i])) vis[i] = 1,q.push(i),lim[i] = inf; else vis[i] = 0;}
		auto judge = []() -> void
		{
			try(i,1,n) if(tar[i] == 1 and dis[i] > inf) {puts("Impossible"); exit(0);}
			try(i,1,m)
			{
				register int x = d[i].x,y = d[i].y;
				if((!(~tar[x]) and dis[y] <= d[i].l) or (!(~tar[y]) and dis[x] <= d[i].l)) {puts("Impossible");exit(0);}
			}
		};
		spfa(); dijkstra(); judge();
		try(i,1,m)
		{
			register int x = d[i].x,y = d[i].y;
			if(!(~tar[x]) or !(~tar[y])) printf("%d\n",d[i].l);
			else printf("%d\n",max(dis[x],dis[y]) > d[i].r ? d[i].l : max(d[i].l,max(dis[x],dis[y])));
		}
		return 0;
	}
}
signed main() {return xin::main();}

计数

这个我们首先考虑一个没有限制的做法。

我们设 \(f_i\) 为子树大小为 \(i\),然后方案数为 \(f_i\)

转移:

\[f_0 = 1\\ f_i = \sum_{j=0}^{n} f_j * f_{n-j-1} \]

然后 \(20pts\) 到手。。。

然后我们推广

有限制了就是限制其深度。。

然后记录一个 \(lim\) 也就能转移了



#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 = 1e3+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 mod = inf;
	int n,T,m;
	int f[maxn],dp[maxn][maxn],lim[maxn][3];

	int dfs(int i,int j)
	{
		if(~dp[i][j]) return dp[i][j]; if(!j) return 1;
		dp[i][j] = 0;
		try(k,max(lim[i][0],0),min(lim[i][1],j-1))
			(dp[i][j] += dfs(i+1,k) * dfs(i+1+k,j-1-k) % mod) %= mod;
		return dp[i][j];
	}
	inline short main()
	{
		file(count);
		io >> T;
		while(T--)
		{
			io >> n >> m;
			if(!m)
			{
				f[0] = 1; f[1] = 1;
				try(i,2,n) try(j,0,i-1)
					(f[i] += f[j] * f[i-j-1] % mod) %= mod;
				cout<<f[n]<<endl;
				memset(f,0,sizeof(int) * (n + 1));
				continue;
			}
			try(i,1,n) {lim[i][0] = 0,lim[i][1] = n - i + 1;}
			memset(dp,-1,sizeof(dp));
			try(i,1,m)
			{
				register int x,y; io >> x >> y;
				if(x < y) lim[x][1] = min(lim[x][1],y - x - 1);
				else lim[y][0] = max(lim[y][0],x - y);
			}
			printf("%lld\n",dfs(1,n));
		}
		return 0;
	}
}
signed main() {return xin::main();}
posted @ 2021-09-17 19:59  NP2Z  阅读(33)  评论(0编辑  收藏  举报