• NOIP2016 DAY2


    组合数问题

    利用杨辉三角, 前缀和优化。

    $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" <<"
    "
    #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
    ", cnt[n][n]);
        	else printf("%lld
    ", cnt[n][m]);
    	}
    	return 0;
    }
    
    

    蚯蚓

    用优先队列保存每一只蚯蚓,每一次弹出栈顶元素。

    如何处理没一只蚯蚓增加一定的长度呢?转换思路。每次只有两只新产生的蚯蚓没被加,其他的全部被加了, 等价于那两只减了。 所以可以记录累计加的长度, 有几只没被加的就减去。

    100分

    要发现题目中的单调性。先被切掉的蚯蚓分成的蚯蚓

    假设有两只蚯蚓a, b, a > b。

    那么先切a,成为(a_1, a_2) ,t秒之后切b,此时(a_1) 的长度为(a imes P + t imes q), (a_2)的长度为(a imes (1 -P) + t imes q) ,t秒之后b的长度变为了((b + t * q) * p)

    (b_1) 的长度为$b imes P + t imes q imes p $, (b_2)的长度为(b imes (1 -P) + t imes q imes (1 - p))

    可以明显的看出(a_1 > b_1, a_2 > b_2), 可以将这两堆分别储存,每次从三个堆之中找出最大的,切开,放回去。

    #include <cstdio>
    #include <iostream>
    #include <queue>
    #include <algorithm>
    #define orz cout << "AK IOI" <<"
    "
    
    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
    ", left, right);
    		add += q;
    		left -= add, right -= add;
    		cut1[++t1] = left, cut2[++t2] = right;
    		if(i % t == 0) printf("%d ", top);
    	}
    	printf("
    ");
    	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"<<"
    "
    
    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
    ", f[(1 << n) - 1]);
    	}
        //fclose(stdin);
        //fclose(stdout);
        return 0;
    }
    
    
  • 相关阅读:
    sklearn库学习笔记1——preprocessing库
    juypter notetbook
    信用卡欺诈
    matplotlib1
    python一行输入多个数
    pandas数据预处理
    pandas基础用法
    numpy简单用法2
    numpy 简单用法
    简单循环
  • 原文地址:https://www.cnblogs.com/yangchengcheng/p/14890827.html
Copyright © 2020-2023  润新知