// // // // // // // // // // // // // //

$NOIP\ 2016\ Day2$ 模拟考试 题解报告

\(NOIP\ 2016\ Day2\) 模拟考试 题解报告

得分情况

\(T1\) \(90\ Pts\)

\(T2\ 45\ Pts\) (\(Loj\) 数据)

\(T2\ 65\ Pts\) (洛谷 数据)

\(T3\ 5\ Pts\)

总分: \(140/160\ Pts\)

考试过程

\(T1\) 看一眼 组合数 数论 打表 看到杨辉三角 先写的递推 大概 \(70\) 然后看到 \(k\) 直接取模 能过 \(90\)\(95\) 一个小时 先扔掉 去看 \(T2\) 对着数据点一个一个写 写完 \(n^2\) 的又把 \(q = 0\) 的单独拿出来 但是还是超时 大概不是很到一个小时 后面的时间死磕 \(T3\) 但并没有拿多少分

题解

\(T1\) 组合数问题

\(O(n^2)\) 预处理 + 二维前缀和优化把查询优化到 \(O(1)\) 就能过

代码

/*
  Time: 6.15
  Worker: Blank_space
  Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#define int long long
#define Min(x, y) ((x) < (y) ? (x) : (y))
/*--------------------------------------头文件*/
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
	freopen("problem.in", "r", stdin);
	freopen("problem.out", "w", stdout);
}
/*----------------------------------------文件*/
int T, k, n, m, f[2021][2021], ans[2021][2021];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
void work() {
	n = read(); m = read();
	printf("%lld\n", ans[n][Min(n, m)]);
}
/*----------------------------------------函数*/
signed main() {
	File();
	T = read(); k = read(); f[0][0] = 1;
	for(int i = 1; i <= 2000; i++)
	{
		for(int j = 1; j <= i; j++)
		{
			f[i][i - j] = f[i][j] = (f[i - 1][j - 1] + f[i - 1][j]) % k;
			ans[i][j] = ans[i - 1][j] + ans[i][j - 1] - ans[i - 1][j - 1];
			if(!f[i][j]) ans[i][j]++;
		}
		ans[i][i + 1] = ans[i][i];
	}
	while(T--) work();
	return 0;
}

\(T2\) 蚯蚓

实际上写了 \(70\) 分的 复杂度大概是能卡过的 但是似乎由于优先队列的常数过大 后面的六个点就过了一个 吸氧的话分会高一些

同样没有吸氧的情况下 洛谷数据比 \(LOJ\) 的数据高 \(20\) 分 ...

正解

题中本身隐含单调性 先被切开的蚯蚓一定比后被切开的蚯蚓长 可以将两堆分别存储 每次切的时候从三堆中取最大的 切完依次放回 时间复杂度 \(O(m)\)

维护三个队列 第一个表示原蚯蚓 第二个表示切开后较长的蚯蚓 第三个表示切开后较短的蚯蚓

先将原序列排序 省去每一秒增加每只蚯蚓的长度的操作 转换成在查询砍哪只蚯蚓时 把增加的长度算到蚯蚓的总长度上

每次在三个队列中找最长的 切开后放到二三里面

统计答案的时候将三个队列合并 排序输出

代码

/*
  Time: 6.15
  Worker: Blank_space
  Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
/*--------------------------------------头文件*/
const int B = 1e5 + 7;
const int C = 8e6 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*------------------------------------常量定义*/
inline void File() {
	freopen("earthworm.in", "r", stdin);
	freopen("earthworm.out", "w", stdout);
}
/*----------------------------------------文件*/
int n, m, q, u, v, t, Q[3][C], l[3], r[3], a[C], cnt;
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
bool cmp(int x, int y) {return x > y;}
void work(int x) {
	int id, y, z, max = 0;
	if(l[0] <= r[0] && Q[0][l[0]] + x * q > max) max = Q[0][l[0]] + x * q, id = 0;
	if(l[1] <= r[1] && Q[1][l[1]] + (x - l[1]) * q > max) max = Q[1][l[1]] + (x - l[1]) * q, id = 1;
	if(l[2] <= r[2] && Q[2][l[2]] + (x - l[2]) * q > max) max = Q[2][l[2]] + (x - l[2]) * q, id = 2;
	l[id]++; y = 1ll * max * u / v; z = max - y; if(y < z) Swap(y, z); Q[1][r[1]++] = y; Q[2][r[2]++] = z;
	if(!((x + 1) % t)) printf("%d ", max);
}
void del(int i) {
	if(i) while(l[i] <= r[i]) a[++cnt] = Q[i][l[i]] + (m - l[i]) * q, l[i]++;
	else while(l[i] <= r[i]) a[++cnt] = Q[i][l[i]] + m * q, l[i]++;
}
/*----------------------------------------函数*/
int main() {
	File();
	n = read(); m = read(); q = read(); u =  read(); v = read(); t = read();
	l[0] = r[0] = l[1] = r[1] = l[2] = r[2] = 1;
	for(int i = 1; i <= n; i++) Q[0][i] = read(); r[0] = n;
	std::sort(Q[0] + 1, Q[0] + 1 + n, cmp);
	for(int i = 1; i <= m; i++) work(i - 1);
	for(int i = 0; i <= 2; i++) del(i);
	std::sort(a + 1, a + 1 + cnt, cmp); puts("");
	for(int i = t; i <= m + n; i += t) printf("%d ", a[i]);
	return 0;
}

\(T3\) 愤怒的小鸟

\(n^2\) 枚举点对 待定系数法直接解方程 把 \(x\) 相等的判出去 把解出来 \(a > 0\) 的判出去 对于算出来的每一条抛物线 再枚举每个点 将经过的所有点都压进去 然后 \(dp\)

状态: \(f_S\) 表示经过点集为 \(S\) 时所用抛物线条数

转移时外层枚举状态 内层尝试将一个点纳入经过的集合 转移考虑将多少个点同时纳入

代码:

/*
  Time: 6.15
  Worker: Blank_space
  Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#include<cstring>
#define Abs(x) ((x) < 0 ? -(x) : (x))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define emm(x, a) memset(x, a, sizeof x)
/*--------------------------------------头文件*/
const double eps = 1e-9;
/*------------------------------------常量定义*/
inline void File() {
	freopen("angrybirds.in", "r", stdin);
	freopen("angrybirds.out", "w", stdout);
}
/*----------------------------------------文件*/
int T, n, m, cnt, s[20][20], f[(1 << 18) + 2], ans;
double x[20], y[20];
/*------------------------------------变量定义*/
inline int read() {
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
/*----------------------------------------快读*/
void work() {
	n = read(); m = read(); emm(f, 63); emm(s, 0); f[0] = 0;
	for(int i = 1; i <= n; i++) scanf("%lf%lf", x + i, y + i);
	for(int i = 1; i < n; i++) for(int j = i + 1; j <= n; j++)
	{
		if(Abs(x[i] - x[j]) < eps) continue;
		double a = (y[i] / (x[i] * x[i] - x[i] * x[j]) - y[j] / (x[i] * x[j] - x[j] * x[j]));
		double b = (y[i] * x[j] * x[j] - y[j] * x[i] * x[i]) / (x[i] * x[j] * x[j] - x[j] * x[i] * x[i]);
		if(a >= 0 || Abs(a) < eps) continue;
		for(int k = 1; k <= n; k++) if(Abs(a * x[k] * x[k] + b * x[k] - y[k]) < eps) s[i][j] |= 1 << k - 1;
	}
	for(int S = 0; S < 1 << n; S++) for(int i = 1; i <= n; i++) if(!(1 << i - 1 & S))
	{
		for(int j = i; j <= n; j++)
		{
			if(i == j) f[S | (1 << i - 1)] = Min(f[S | (1 << i - 1)], f[S] + 1);
			if(Abs(x[i] - x[j]) < eps) continue;
			f[S | s[i][j]] = Min(f[S | s[i][j]], f[S] + 1);
		}
		break;
	}
	printf("%d\n", f[(1 << n) - 1]);
}
/*----------------------------------------函数*/
int main() {
//	File();
	T = read(); while(T--) work();
	return 0;
}
posted @ 2021-06-16 21:00  Blank_space  阅读(45)  评论(0编辑  收藏  举报
// // // // // // //