ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

NIOP2016 DAT2

2021-06-16 20:02:40  阅读:149  来源: 互联网

标签:NIOP2016 ch read times && DAT2 include 蚯蚓


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,ch,read,times,&&,DAT2,include,蚯蚓
来源: https://www.cnblogs.com/yangchengcheng/p/14890827.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有