NIOP2016 DAT2
Posted _程门立雪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NIOP2016 DAT2相关的知识,希望对你有一定的参考价值。
NIOP2016 DAT2
组合数问题
利用杨辉三角, 前缀和优化。
$C_n ^m = C_n ^{n-m} $
$ C_n ^m = C_{n - 1} ^{m - 1} + C_{n - 1} ^m$
原谅我足够菜不知道组合数与杨辉三角有关系这一常识
#include <cstdio>
#include <iostream>
#include <cstring>
#define orz cout << "AK IOI" <<"\\n"
#define int long long
using namespace std;
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;
}
int T, k, n, m, cnt[2000][2000], c[2000][2000];
bool s[2000][2000];
void init()
{
c[0][0] = 1;
c[1][0] = c[1][1] = 1;
for(int i = 2; i <= 2000; i++)
{
c[i][0] = 1;
for(int j = 1; j <= i; j++)
{
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % k;
cnt[i][j] = cnt[i - 1][j] + cnt[i][j - 1] - cnt[i - 1][j - 1];
if(!c[i][j]) cnt[i][j]++;
}
cnt[i][i + 1] = cnt[i][i];//为了更新右边
}
}
signed main()
{
//freopen("problem.in","r",stdin);
//freopen("problem.out","w",stdout);
T = read(), k = read(); init();
while(T--)
{
n = read(), m = read();
if(m > n) printf("%lld\\n", cnt[n][n]);
else printf("%lld\\n", cnt[n][m]);
}
return 0;
}
蚯蚓
用优先队列保存每一只蚯蚓,每一次弹出栈顶元素。
如何处理没一只蚯蚓增加一定的长度呢?转换思路。每次只有两只新产生的蚯蚓没被加,其他的全部被加了, 等价于那两只减了。 所以可以记录累计加的长度, 有几只没被加的就减去。
100分
要发现题目中的单调性。先被切掉的蚯蚓分成的蚯蚓
假设有两只蚯蚓a, b, a > b。
那么先切a,成为\\(a_1, a_2\\) ,t秒之后切b,此时\\(a_1\\) 的长度为\\(a \\times P + t \\times q\\), \\(a_2\\)的长度为\\(a \\times (1 -P) + t \\times q\\) , \\(b_1\\) 的长度为\\(b \\times P + t \\times q\\), \\(b_2\\)的长度为\\(b \\times (1 -P) + t \\times q\\)
可以明显的看出\\(a_1 > b_1, a_2 > b_2\\), 可以将这两堆分别储存,每次从三个堆之中找出最大的,切开,放回去。
#include <cstdio>
#include <iostream>
#include <queue>
#include <algorithm>
#define orz cout << "AK IOI" <<"\\n"
using namespace std;
const int maxn = 7e6 + 10;
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;
}
int n, m, q, u, v, t, top, add, now[maxn], cut1[maxn], cut2[maxn];
priority_queue<int> ans;
bool cmp(int a, int b)
{
return a > b;
}
int main()
{
//freopen("P2827_2.in","r",stdin);
//freopen("P2827_2.out","w",stdout);
n = read(), m = read(), q = read(), u = read(), v = read(), t = read();
double p = (double) u / v;
for(int i = 1; i <= n; i++) now[i] = read();
int t0 = n, t1 = 0, t2 = 0, h = 1, h1 = 1, h2 = 1;
sort(now + 1, now + n + 1, cmp);
for(int i = 1; i <= m; i++)//为了找到被切的蚯蚓
{
if(h > t0)
{
if(cut1[h1] > cut2[h2]) top = cut1[h1++];
else top = cut2[h2++];
}
else
{
if(now[h] >= cut1[h1] && now[h] >= cut2[h2]) top = now[h++];
else if(cut1[h1] >= cut2[h2] && now[h] <= cut1[h1]) top = cut1[h1++];
else top = cut2[h2++];
}
top += add;
int left = p * (double)top, right = top - left;
//printf("ha = %d %d\\n", left, right);
add += q;
left -= add, right -= add;
cut1[++t1] = left, cut2[++t2] = right;
if(i % t == 0) printf("%d ", top);
}
printf("\\n");
for(int i = h; i <= t0; i++) ans.push(now[i]);
for(int i = h1; i <= t1; i++) ans.push(cut1[i]);
for(int i = h2; i <= t2; i++) ans.push(cut2[i]);
for(int i = 1; ans.size(); i++)
{
if(i % t == 0) printf("%d ", ans.top() + add);
ans.pop();
}
return 0;
}
愤怒的小鸟
状压dp
f[S]表示已经死了的猪的集合状态为S时,最少要发射的鸟数。
f[0] = 0
f[s|(1 << (j - 1))] = min(f[s] + 1)
\\(f[i|line[j][k]] = min(f[i|line[j][k]], f[i] + 1)\\)
根据每两个点算出一条抛物线,然后枚举每一头猪所在的位置,能被抛物线打到的位置进行状压。
然后进行dp。
/*
状压dp !!!!!感觉有哪没理解
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#define orz cout<<"AK IOI"<<"\\n"
using namespace std;
const double eps = 1e-8;
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 * 10 + ch - \'0\'; ch = getchar();}
return x * f;
}
int T, n, m, map[20][20], line[20][20], f[1 << 20], s[1 << 20];
double x[20], y[20];
void init()
{
for(int i = 0; i < (1 << 18); i++)//枚举每一种状态
{
int j = 1;
for(; j <= 18 && i & (1 << (j - 1)); j++);//i这个状态第j头猪是否被打掉
s[i] = j;//dp的起始位置 状态内第一个0的位置
}
}
void fc(double &a, double &b, int i, int j)
{
a = -(y[i] * x[j] - y[j] * x[i]) / (x[j] * x[j] * x[i] - x[i] * x[i] * x[j]);
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]);
}
int main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
init();
T = read();
while(T--)
{
memset(line, 0, sizeof line);
memset(f, 1, sizeof f);
f[0] = 0;
n = read(), m = read();
for(int i = 1; i <= n; i++) scanf("%lf%lf", &x[i], &y[i]);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
double a, b;
fc(a, b, i, j);
if(a > -eps) continue;//如果开口方向向上
for(int k = 1; k <= n; k++)
{
if(fabs(a * x[k] * x[k] + b * x[k] - y[k]) < eps)//枚举每一个点看看是否会被打掉
line[i][j]|= (1 << (k - 1));
}
}
}
for(int i = 0; i < (1 << n); i++)
{
int j = s[i];
f[i|(1 << (j - 1))] = min(f[i|(1 << (j - 1))], f[i] + 1);
for(int k = 1; k <= n; k++)
f[i|line[j][k]] = min(f[i|line[j][k]], f[i] + 1);
}
printf("%d\\n", f[(1 << n) - 1]);
}
//fclose(stdin);
//fclose(stdout);
return 0;
}
以上是关于NIOP2016 DAT2的主要内容,如果未能解决你的问题,请参考以下文章
niop 2003 传染病控制 (哎呀我氧化钙 坑了好久的搜索题)
五大学科竞赛NIOP全国青少年信息学奥林匹克分区联赛竞赛大纲
csharp C#代码片段 - 使类成为Singleton模式。 (C#4.0+)https://heiswayi.github.io/2016/simple-singleton-pattern-us