2020.1.9考试总结

T1
数据范围很合适..
第一档就是暴力枚举
第二档就是数位DP
第三档就是矩阵乘法
丢一下学长的博客

#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
using namespace std;
LL n;
const int mod = 1e9 + 7;
struct ju 
{
	LL c[4][4];
	friend ju operator *(const ju &a, const ju &b) 
	{
		ju c;
		memset(c.c, 0, sizeof(c.c));
		for (int i = 1; i <= 3; ++i)
			for (int j = 1; j <= 3; ++j)
				for (int k = 1; k <= 3; ++k)
					c.c[i][j] += a.c[i][k] * b.c[k][j] % mod, c.c[i][j] %= mod;
		return c;
	}
} base, ans;
LL ksm(LL a, LL b, LL mod) 
{
	LL res = 1;
	for (; b; b >>= 1, a = a * a % mod)
		if (b & 1)res = res * a % mod;
	return res;
}
ju ksm(ju a, LL b) 
{
	ju res;
	memset(res.c, 0, sizeof(res.c));
	for (int i = 1; i <= 3; ++i)res.c[i][i] = 1;
	for (; b; b >>= 1, a = a * a)
		if (b & 1)res = res * a;
	return res;
}
int main() 
{
	freopen("number.in", "r", stdin);
	freopen("number.out", "w", stdout);
	cin >> n;
	base.c[1][1] = 3; base.c[1][2] = 2; base.c[1][3] = 0;
	base.c[2][1] = 1; base.c[2][2] = 3; base.c[2][3] = 1;
	base.c[3][1] = 0; base.c[3][2] = 2; base.c[3][3] = 3;
	ans .c[1][1] = 3;
	ans .c[2][1] = 1;
	ans .c[3][1] = 0;
	ans = ksm(base, n - 1) * ans;
	(((ans.c[1][1] -= ksm(2, n, mod) + ksm(4, n, mod) % mod) %= mod) += mod) %= mod;
	ans.c[1][1] += ksm(3, n, mod);
	cout << ans.c[1][1] % mod;
	fclose(stdin); fclose(stdout);
	return 0;
}

T2
发现一个位置的值是奇数当且仅当 它所在的行加的次数+它所在的列加的次数 的和是奇数。
当有x行加了奇数次,y列加了奇数次,那么奇数个数就是(n-x)y+x(m-y)
枚举x,可以解方程得到y,特判一下(2xn&&xmk)的情况(化一化式子就知道了),贡献就是(displaystyle C_n^xC_m^yC_{frac{r-x}{2}+n-1}^{n-1}C_{frac{c-y}{2}+m-1}^{m-1})
大力卡一卡边界就行了。

#include<iostream>
#include<cstdio>
#define int long long
#define LL long long
#define DB double
using namespace std;
LL n, m, r, c, k, ans;
const int N = 400010, M = 200000, mod = 1e9 + 7;
LL jc[N], inv[N];
inline int read() 
{
	int res = 0; char ch = getchar(); bool XX = false;
	for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
	for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
	return XX ? -res : res;
}
LL ksm(LL a, LL b, LL mod) 
{
	LL res = 1;
	for (; b; b >>= 1, a = a * a % mod)
		if (b & 1)res = res * a % mod;
	return res;
}
void YYCH() 
{
	jc[0] = jc[1] = inv[0] = inv[1] = 1;
	for (int i = 2; i <= M; ++i)jc[i] = jc[i - 1] * i % mod;
	inv[M] = ksm(jc[M], mod - 2, mod);
	for (int i = M - 1; i >= 1; --i)inv[i] = inv[i + 1] * (i + 1) % mod;
}
LL C(LL n, LL m) {if (n < m)return 0; return jc[n] * inv[m] % mod * inv[n - m] % mod;}
void suan(LL x, LL y) 
{
	if (((r - x) & 1) || ((c - y) & 1))return;
	ans += C(n, x) * C(m, y) % mod * C(((r - x) >> 1) + n - 1, n - 1) % mod * C(((c - y) >> 1) + m - 1, m - 1) % mod, ans %= mod;
}
DB jue(DB x) {return x > 0 ? x : -x;}
int zheng(DB x) 
{
	return jue(x - (int)x) < 1e-3;
}
signed main() 
{
	freopen("matrix.in", "r", stdin);
	freopen("matrix.out", "w", stdout);
	cin >> n >> m >> r >> c >> k;
	YYCH();
	for (int x = (r & 1); x <= n; x += 2) 
	{
		if (n == 2 * x) 
		{
			if (x * m == k) for (int y = (c & 1); y <= m; y += 2)suan(x, y);
		} 
		else 
		{
			DB y = (DB)(k - x * m) / (n - 2 * x);
			if ((int)y < 0 || !zheng(y))continue;
			suan(x, y);
		}
	}
	cout << ans;
	fclose(stdin); fclose(stdout);
	return 0;
}

T3
前置题目线段树做法
首先离线...
原来的题目限制的只有自己这个位置,现在变成了它及它前边的k个位置。
线段树维护 区间取min,单点查询 即可。
考场上没开大空间直接凉凉...
好像这道题莫队跑得挺快的。

#include<algorithm>
#include<iostream>
#include<cstdio>
#define lson (k<<1)
#define rson ((k<<1)|1)
#define LL long long
#define DB double
using namespace std;
int n, m, q, k;
const int N = 400010, inf = 1e9;
int vis[N], a[N], ans[N], to[N][11], las[N], tr[N << 2], lz[N << 2];
struct Ask {int l, r, ans, id;} Q[N];
int my1(const Ask &a, const Ask &b) {return a.l < b.l;}
int my2(const Ask &a, const Ask &b) {return a.id < b.id;}
inline int read() 
{
	int res = 0; char ch = getchar(); bool XX = false;
	for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
	for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
	return XX ? -res : res;
}
void Write(int x, int opt) 
{
	if (opt && !x)putchar('0');
	if (!x)return; Write(x / 10, 0);
	putchar((x - x / 10 * 10) + '0');
}
void build(int k, int l, int r) 
{
	lz[k] = inf;
	if (l == r) 
	{
		tr[k] = ans[l];
		return;
	}
	int mid = (l + r) >> 1;
	build(lson, l, mid); build(rson, mid + 1, r);
}
inline void cd(int k) 
{
	lz[lson] = min(lz[lson], lz[k]); lz[rson] = min(lz[rson], lz[k]);
	lz[k] = inf;
}
void change(int k, int l, int r, int x, int y, int v) 
{
	if (x <= l && r <= y) 
	{
		lz[k] = min(lz[k], v);
		return;
	}
	if (lz[k] != inf)cd(k);
	int mid = (l + r) >> 1;
	if (x <= mid)change(lson, l, mid, x, y, v);
	if (mid + 1 <= y)change(rson, mid + 1, r, x, y, v);
}
int ask(int k, int l, int r, int pos) 
{
	if (l == r) 
	{
		return min(lz[k], tr[k]);
	}
	if (lz[k] != inf)cd(k);
	int mid = (l + r) >> 1;
	if (pos <= mid)return ask(lson, l, mid, pos);
	else return ask(rson, mid + 1, r, pos);
}
inline void solve2() 
{
	for (int i = 1; i <= q; ++i) 
	{
		Q[i].l = read(); Q[i].r = read(); Q[i].id = i;
	}
	sort(Q + 1, Q + 1 + q, my1);
	int now = 1;
	for (int i = 1; i <= m; ++i) 
	{
		for (int j = max(1, a[i] - k + 1); j <= a[i]; ++j) 
		{
			vis[j] = 1;
			to[las[j]][a[las[j]] - j] = i;
			las[j] = i;
		}
		while (vis[now])++now;
		ans[i] = now;
	}
	for (int i = 1; i <= n; ++i)to[las[i]][a[las[i]] - i] = m + 1;
	build(1, 1, m);
	now = 1; int pos;
	for (int i = 1; i <= m; ++i) 
	{
		while (Q[now].l == i) 
		{
			Q[now].ans = ask(1, 1, m, Q[now].r);
			++now;
		}
		for (int j = max(1, a[i] - k + 1); j <= a[i]; ++j) 
		{
			pos = to[i][a[i] - j] - 1;
			change(1, 1, m, i, pos, j);
		}
	}
	sort(Q + 1, Q + 1 + q, my2);
	for (int i = 1; i <= q; ++i) 
	{
		if (Q[i].ans > n - k + 1)puts("-1");
		else Write(Q[i].ans, 1), putchar('
');
	}
}
int main() 
{
	freopen("stall.in", "r", stdin);
	freopen("stall.out", "w", stdout);
	cin >> n >> m >> q >> k;
	for (int i = 1; i <= m; ++i)a[i] = read();
	solve2();
	fclose(stdin); fclose(stdout);
	return 0;
}

任何时候,都不要自信到连暴力分都不要。

原文地址:https://www.cnblogs.com/wljss/p/12173015.html