NOIP模拟3

三元

构造题,显然第一列要填 \(n\)\(0、n\)\(1\)\(n\)\(2\),所以就直接把 $ 0、1、2$ 按顺序放好
\(0、1、2\)开头的串分为三块
题目要求字典序最大的串字典序最小,所以就尽可能地在\(2\)后面放\(0\),然而都放\(0\)显然会重复,所以就在最后一列按照\(0、1、2\)的顺序从上往下放,然而\(n\)大于\(3\)的时候又会重复,所以要把前面的一个\(0\)换成\(1\),还不够就把\(0\)换成\(2\),再不够就继续往前一列换,为了方便替换的时候依然按照\(0、1、2\)的顺序放,就会发现每一列都有一个循环,而每一列的循环的长度都是\(3^{L-i+1}\)(\(L\)是串的长度,\(i\)是第几列), 因此可以直接按照循环放,而为了保证每一列\(0、1、2\)的出现次数都为\(n\),应在上面的块中改变\(0、1、2\)的顺序,改为\(2、0、1\)\(1、2、0\)即可,不理解可以手模一下

code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<cmath>
using namespace std;

#define Miuna printf ("dai  suki...")
#define mizuki signed 
#define love (1209 & 322 & 901)

namespace LRH 
{
	template <typename Shiodome_miuna> inline void in (Shiodome_miuna &x)
	{
		x = 0;
		char f = 0; char ch;
		while (!isdigit (ch = getchar ())) if (ch == '-') f = 1;
		do
		{
			x = (x << 1) + (x << 3) + (ch ^ 48);
		} while (isdigit (ch = getchar ()));
		if (f) x = -x;
	}
	int stk[20], tp;
	template <typename Shiodome_miuna> inline void ot (Shiodome_miuna x, int f = 2)
	{
		if (x < 0) putchar ('-'), x = -x;
		do
		{
			stk[++ tp] = x % 10;
			x /= 10;
		} while (x);
		while (tp)
		{
			putchar (stk[tp --] | 48);
		}
		if (f == 1) putchar ('\n');
		if (!f) putchar (' ');
	}
}using namespace LRH;
typedef long long ll;
const int maxn = 5e4 + 10;
int n, L;
int a[3 * maxn][20];
int up[20];
mizuki main ()
{
	freopen ("three.in", "r", stdin);
	freopen ("three.out", "w", stdout);
	in (n), in (L);
	int nn = n << 1, nnn = n * 3;
	for (int i = 1; i <= L; ++ i) up[i] = pow (3, L - i);
	for (int i = 1; i <= n; ++ i) a[i][1] = 0;
	for (int i = n + 1; i <= nn; ++ i) a[i][1] = 1;
	for (int i = nn + 1; i <= nnn; ++ i) a[i][1] = 2;
	for (int l = 2; l <= L; ++ l)
	{
		for (int i = 1; i <= n; ++ i)
		{
			int tmp = i % (3 * up[l]);
			if (tmp == 0) tmp = 3 * up[l];
			int kk = (tmp - 1) / up[l];
			if (kk == 0) a[i][l] = 2;
			else if (kk == 1) a[i][l] = 0;
			else if (kk == 2) a[i][l] = 1;
		}
	}
	for (int l = 2; l <= L; ++ l)
	{
		for (int i = n + 1; i <= nn; ++ i)
		{
			int k = i - n;
			int tmp = k % (3 * up[l]);
			if (tmp == 0) tmp = 3 * up[l];
			if ((tmp - 1) / up[l] == 0) a[i][l] = 1;
			else if ((tmp - 1) / up[l] == 1) a[i][l] = 2;
			else if ((tmp - 1) / up[l] == 2) a[i][l] = 0;
		}
	}
	for (int l = 2; l <= L; ++ l)
	{
		for (int i = nn + 1; i <= nnn; ++ i)
		{
			int k = i - nn;
			int tmp = k % (3 * up[l]);
			if (tmp == 0) tmp = 3 * up[l];
			if ((tmp - 1) / up[l] == 0) a[i][l] = 0;
			else if ((tmp - 1) / up[l] == 1) a[i][l] = 1;
			else if ((tmp - 1) / up[l] == 2) a[i][l] = 2;
		}
	}
	for (int i = 1; i <= nnn; ++ i)
	{
		for (int l = 1; l <= L; ++ l)
		{
			ot (a[i][l]);
		}
		putchar ('\n');
	}
	return love;
}

鹅国

非正解,是\(O(nk^3)\)的,\(c_i\)\(c_{i-1}\)的倍数,也就是说\(c_i\)是可以替换成几个\(c_{i-1}\)的,于是就可以想\(DP\)
\(f_{i, J,k}\)\(g_{i, J, k}\)表示后\(i\)个币一共用了\(J\)个,用了\(k\)个第\(i\)种币的最大\(/\)小重量
可以枚举将几个第\(i\)种币转成第\(i - 1\)种币,设转化\(s\)个,一个\(i\)种币可以转成\(t\)\(i-1\)种币,则有转移
\(f_{i, J, k} +s\times w_i+(s\times t)\times w_{i-1}→ f_{i-1,J+s\times t-s, s\times t}\)
发现初始状态不好设
因为我们是倒着枚举\(i\),所以可以尽量先选面值大的币,于是就可以处理出来初始状态来
然而直接这样内存会炸,所以用滚动数组,所以要在转移过程中将初始状态加进去,具体见代码

code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
using namespace std;

#define Miuna printf ("dai  suki...")
#define mizuki signed 
#define love (1209 & 322 & 901)

namespace LRH 
{
	template <typename Shiodome_miuna> inline void in (Shiodome_miuna &x)
	{
		x = 0;
		char f = 0; char ch;
		while (!isdigit (ch = getchar ())) if (ch == '-') f = 1;
		do
		{
			x = (x << 1) + (x << 3) + (ch ^ 48);
		} while (isdigit (ch = getchar ()));
		if (f) x = -x;
	}
	int stk[20], tp;
	template <typename Shiodome_miuna> inline void ot (Shiodome_miuna x, int f = 2)
	{
		if (x < 0) putchar ('-'), x = -x;
		do
		{
			stk[++ tp] = x % 10;
			x /= 10;
		} while (x);
		while (tp)
		{
			putchar (stk[tp --] | 48);
		}
		if (f == 1) putchar ('\n');
		if (!f) putchar (' ');
	}
}using namespace LRH;
typedef long long ll;
#define int ll
const int maxn = 1e3 + 10;
const int inf = 4e18;
int n, k;
ll ans1, ans2, p;
struct miuna 
{
	ll c, w;
}a[65];
ll f[2][1010][1010], g[2][1010][1010];
int v[65];
mizuki main ()
{
	freopen ("goose.in", "r", stdin);
	freopen ("goose.out", "w", stdout);
	in (n), in (k), in (p);
	for (int i = 1; i <= n; ++ i) in (a[i].c), in (a[i].w);
	if (p % a[1].c) return (puts ("-1"), love);
	memset (f, 127, sizeof (f)), memset (g, 128, sizeof (g));
	ll tmp = p;
	for (int i = n; i >= 1; -- i) v[i] = tmp / a[i].c, tmp %= a[i].c;
	f[0][v[n]][v[n]] = v[n] * a[n].w, g[0][v[n]][v[n]] = v[n] * a[n].w;
	int op = 0;
	for (int i = n; i >= 2; -- i)
	{
		op ^= 1;
		int t = a[i].c / a[i - 1].c;
		for (int J = 0; J <= k; ++ J)
		{
			for (int K = 0; K <= J; ++ K)
			{
				if (f[op ^ 1][J][K] >= inf && g[op ^ 1][J][K] <= -inf) continue;
				for (int s = 0; s <= K; ++ s)
				{
					int o = s * t + v[i - 1];
					if (J + o - s > k) break;
					f[op][J + o - s][o] = min (f[op][J + o - s][o], f[op ^ 1][J][K] - s * a[i].w + o * a[i - 1].w);
					g[op][J + o - s][o] = max (g[op][J + o - s][o], g[op ^ 1][J][K] - s * a[i].w + o * a[i - 1].w);
				}
				f[op ^ 1][J][K] = inf, g[op ^ 1][J][K] = -inf;
			}
		}
	}
	ll ans1 = inf, ans2 = -inf;
	for (int i = v[1]; i <= k; ++ i) ans1 = min (ans1, f[op][k][i]), ans2 = max (ans2, g[op][k][i]);
	if (ans1 == inf) return puts ("-1"), love;
	ot (ans1, 0), ot (ans2, 1);
	return love;
}

楼盘

离谱\(DP\)
我这么\(J\)显然是不会的

矩形

对于每个\(i\),可以先单调栈预处理出来以它为最小值的区间
设所有矩形的面积排好序后组成的集合为\(A\)
二分求\(A_L\),要求有多少个矩形面积小于等于\(mid\),下面直接贺过来题解
\(f(s)\)为面积小于等于\(s\)的矩形个数
image
image

接下来对于每个\(h_i\)求出\(len\times h_i\)大于\(A_L\)最小的\(len\)
然后求出这个\(len\)可以用几次,塞进一个按\(len\times h_i\)排序的小根堆里,每次输出之后将下一个不小于它的数塞进去

code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#include<set>
using namespace std;

#define Miuna printf ("dai  suki...")
#define mizuki signed 
#define love (1209 & 322 & 901)

namespace LRH 
{
	template <typename Shiodome_miuna> inline void in (Shiodome_miuna &x)
	{
		x = 0;
		char f = 0; char ch;
		while (!isdigit (ch = getchar ())) if (ch == '-') f = 1;
		do
		{
			x = (x << 1) + (x << 3) + (ch ^ 48);
		} while (isdigit (ch = getchar ()));
		if (f) x = -x;
	}
	int stk[20], tp;
	template <typename Shiodome_miuna> inline void ot (Shiodome_miuna x, int f = 2)
	{
		if (x < 0) putchar ('-'), x = -x;
		do
		{
			stk[++ tp] = x % 10;
			x /= 10;
		} while (x);
		while (tp)
		{
			putchar (stk[tp --] | 48);
		}
		if (f == 1) putchar ('\n');
		if (!f) putchar (' ');
	}
}using namespace LRH;
typedef long long ll;
const int maxn = 3e5 + 10;
#define int ll
int n, L, R;
int h[maxn], li[maxn], ri[maxn], a[maxn], b[maxn];
ll S(int x){return x <= 0 ? 0 : x * (x + 1) / 2;}
ll f (int w, int l, int r) {return S (w) - S (w - l - 1) - S (w - r - 1) + S (w - l - r - 2);}
ll ck (ll x)
{
	ll res = 0;
	for (int i = 1; i <= n; ++ i)
	{
		int k = x / h[i];
		res += f (min (k, ri[i] - li[i] + 1), a[i], b[i]);
	}
	return res;
}
struct miuna 
{
	int id, s, c, w;
	friend bool operator < (miuna a, miuna b)
	{
		return a.s > b.s;
	}
};
ll cnt (int i, ll len)
{
	if (li[i] + len - 1 <= i) return min (ri[i] - i + 1, len);
	return min (ri[i] - (li[i] + len - 1) + 1, i - li[i] + 1);
}
priority_queue<miuna>q;
int st[maxn], top;
mizuki main ()
{
	freopen ("rectangle.in", "r", stdin);
	freopen ("rectangle.out", "w", stdout);
	in (n);
	for (int i = 1; i <= n; ++ i) in (h[i]);
	for (int i = 1; i <= n; ++ i)
	{
		while (top && h[st[top]] > h[i]) ri[st[top]] = i - 1, top --;
		st[++ top] = i;
	}
	while (top) ri[st[top --]] = n;
	for (int i = n; i >= 1; -- i)
	{
		while (top && h[st[top]] >= h[i]) li[st[top]] = i + 1, top --;
		st[++ top] = i;
	}
	while (top) li[st[top --]] = 1;
	for (int i = 1; i <= n; ++ i) 
	{
		a[i] = i - li[i];
		b[i] = ri[i] - i;
	}
	in (L), in (R);
	ll l = 0, r = 4e18, ansl;
	while (l <= r)
	{
		ll mid = (l + r) >> 1;
		if (ck (mid) < L) l = mid + 1, ansl = mid;
		else r = mid - 1;
	}
	ansl ++;
	ll up = min (R, ck (ansl));
	for (ll i = L; i <= up; ++ i) ot (ansl, 0);
	ansl ++;
	L = up + 1;
	for (int i = 1; i <= n; ++ i)
	{
		int w = ansl / h[i];
		if (w > (ri[i] - li[i] + 1)) continue;
		q.push ({i, w * h[i], cnt (i, w), w});
	}
	while (L <= R && !q.empty ())
	{
		miuna tmp = q.top ();
		q.pop ();
		tmp.c --;
		if (tmp.c > 0) q.push (tmp);
		else if (tmp.w + 1 <= (ri[tmp.id] - li[tmp.id] + 1)) q.push ({tmp.id, (tmp.w + 1) * h[tmp.id], cnt (tmp.id, tmp.w + 1), tmp.w + 1});
		if (tmp.s < ansl) continue;
		ot (tmp.s, 0);
		L ++;
	}
	return love;
}
posted @ 2022-11-15 21:19  _Mizuki  阅读(12)  评论(3编辑  收藏  举报