Noip2016day2解题报告

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Noip2016day2解题报告相关的知识,希望对你有一定的参考价值。

Noip2016day2解题报告

张炳琪

一.时间安排

T1:50分钟

T2:80分钟

T3:40多分钟

二.答题情况:

T1:100

组合数问题前不久接触过,又加上刚强调的前缀和,加上取模就可以了。刚开始的时候不理解样例,还手模了好久

T2:40

看到7*10^6次方的数据范围,就开始在想On的方法,推了一会推出来了,但是在代码实现上有很多漏洞,所以没A掉

改了输出格式55分

加大了数组范围70分

换用了longlong 100分

T3:20

也没多少时间写这个题目了,就打了个暴力,还打错了。。  解二元一次方程组还是在草纸上写的然后变成代码抄的

三.题目解析

T1:

首先杨辉三角求出所有组合数模k意义下的值

然后维护一个前缀和

每次O(1)查询

T2:

大体思想是先将输入进来的蚯蚓按照从长到短的顺序排序,

再用另外两个类似队列的数组,来分别存放被砍断的蚯蚓这个题目的关键思想就在这里

手模拟一下可以发现,这样的话两个数组都是具有单调性的,这很神奇,所以说这时候整个蚯蚓集团最大的可能

只在三个里面,排序数组中最大的,或者两个队列的队尾

比较一下选择继续同样的操作即可

输出的时候注意格式同样的找到剩余最大的还是从三个数列的头去找

增加的长度不需要暴力加,只需要维护一个值代表整个集团都加的值,但是拿出来切得蚯蚓要减去那个值这样得到的才是真正的值

T3:

状压dp,

首先预处理一个数组note[i][j]表示连接i,j两点做抛物线的时候能打到的小猪

特别的,note【i】【i】 只能打到自己,能打到的小猪分别是谁这个用二进制表示

然后进行dp

转移方程

dp[i | canshe[j][k]] = min(dp[i | canshe[j][k]],dp[i] + 1)//显而易见

但是这样只能得85分

我们需要优化一下

我们发现,当(i & (1 << (j  - 1))时,也就是说枚举的小猪之前打过,那么这种枚举之前以一定枚举过,肯定不优,所以我们只需要加上一个if(!(i&(1 << (j - 1))))特判就能过

四.代码实现

T1:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
int note[2013][2014];
int sum[2013][2014];
int t,k;
int main()
{
    freopen("problem.in","r",stdin);freopen("problem.out","w",stdout);
    scanf("%d%d",&t,&k);
    memset(note,0x3f,sizeof(note));
    note[0][0] = 1;
    for(int i = 1;i <= 2000;i++)
    {
        note[i][0] = 1;
        for(int j = 1;j <= i;j++)
        {
            int op = note[i - 1][j];
            if(op == 0x3f3f3f3f)op = 0;
            int od = note[i - 1][j - 1];
            if(od == 0x3f3f3f3f)od = 0;
            note[i][j] = op + od;
            if(note[i][j] >= k)note[i][j] -= k;
        }
    }
    for(int i = 1;i <= 2000;i++)
        for(int j = 1;j <= 2000;j++)
        {
            if(!note[i][j])sum[i][j] = 1;
            sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
        }
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        printf("%d\n",sum[n][m]);
    }
    //fclose(stdin);fclose(stdout);
    return 0;
}

T2:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;

struct STACK{
    int note[10000010];
    int tp;
    
    STACK()
    {
        note[0] = -2000000000;
    }
    
    void push(int x)
    {
        note[++tp] = x;
    }
    bool empty()
    {
        return tp == 0;
    }
    int top()
    {
        return note[tp];
    }
    void pop()
    {
        tp--;
    }
    void st()
    {
        sort(note + 1,note + tp + 1);
    }
    
}st1;

int note1[10010010];
int note2[10010001];
int front1 = 1,front2 = 1;
int ed1,ed2;
int ID[10010001];
int cnt = 0;
int n,m,q,t;

int  u,v;



int read()
{
    int nm = 0;
    char c = getchar();
    while(c > 9 || c < 0)c = getchar();
    while(c >= 0 && c <= 9)
    {
        nm *= 10;
        nm += c - 0;
        c = getchar();
    }
    return nm;
}

int main()
{
    freopen("earthworm.in","r",stdin);freopen("earthworm.out","w",stdout);
    cin >> n >> m >> q >> u >> v >> t;

    
    for(int i = 1;i <= n;i++)
    {
        st1.push(read());
    }
    st1.st();
    
    for(int i = 0;i < m;i++)
    {
        int zz = max(st1.top(),max(note1[front1],note2[front2]));
        if(zz == st1.top())st1.pop();
        else if(zz == note1[front1])front1++;
        else if(zz == note2[front2])front2++;
        long long  aa = zz + i * q;
        ID[++cnt] = aa;
        long long  bb = aa * u / v ;
        long long  cc = aa - bb ;
        bb -= i * q + q;
        cc -= i * q + q;
        note1[++ed1] = bb;
        note2[++ed2] = cc;
    }
    int op = 0;
    for(int i = 1;i <= cnt;i++)
    {
        op++;
        if(op == t)printf("%d ",ID[i]),op = 0;
    }
    op = 0;
    printf("\n");
    while(!st1.empty() || front1 <= ed1 || front2 <= ed2)
    {
        int ans = 0;
        int flag;
        if(!st1.empty() && ans < st1.top() + m * q)
        {
            ans = st1.top() + m * q;
            flag = 1;
        }
        if(front1 <= ed1 && ans < note1[front1]+ m * q)
        {
            ans = note1[front1]+ m * q;
            flag = 2; 
        }
        if(front2 <= ed2 && ans < note2[front2]+ m * q)
        {
            ans = note2[front2]+ m * q;
            flag = 3;
        }
        
        if(flag == 1) st1.pop();
        if(flag == 2) front1++;
        if(flag == 3) front2++;
        op++;
        if(op == t)
        {
            printf("%d ",ans);
            op = 0;
        }
    }
    return 0;
}

T3:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define eps 1e-8
using namespace std;

struct PIG{
    double x;
    double y;
}pg[19];

int canshe[19][19];//用二进制表示  连接这两个点的抛物线能够打掉哪些点 

int dp[1 << 19];// 表示打掉二进制位的当前状态的小鸟的最少花费 

int t,n,m; 
double a,b;
void jisuan(int x,int y)
{
    double xa = pg[x].x,ya = pg[x].y;
    double xb = pg[y].x,yb = pg[y].y;
    double xaa = xa * xa;
    double xbb = xb * xb;
    
    double op = xb / xa;
    
    xaa *= op;
    xa *= op;
    ya *= op;
    a = (ya - yb) / (xaa - xbb);
    
    b = (yb - a * xbb) / xb;
}

int main()
{
    freopen("angrybirds.in","r",stdin);freopen("angrybirds.out","w",stdout);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(canshe,0,sizeof(canshe));
        memset(dp,0x3e,sizeof(dp));
        dp[0] = 0;
        for(int i = 1;i <= n;i++)
            scanf("%lf%lf",&pg[i].x,&pg[i].y);
        for(int i = 1;i <= n;i++)
        {
            canshe[i][i] = 1 << (i - 1);
            for(int j = i + 1;j <= n;j++)
            {
                jisuan(i,j);
                if(a > 0)continue;
                for(int k = 1;k <= n;k++)
                {
                    double ans = pg[k].x * a * pg[k].x + pg[k].x * b;
                    double zz = ans - pg[k].y;
                    if(zz < 0)zz = -zz;
                    if(zz <= eps)
                    {
                        canshe[i][j] |=(1 << (k - 1));
                    }
                }
            }
        }
        for(int i = 0;i <= (1 << n) - 1;i++)
        {
            for(int j = 1;j <= n;j++)
            if(!(i&(1 << (j - 1))))
                for(int k = j;k <= n;k++)
                {
                    dp[i | canshe[j][k]] = min(dp[i | canshe[j][k]],dp[i] + 1);
                }
        }
        printf("%d\n",dp[(1 << n) - 1]);    
    }
    return 0;
}

 

以上是关于Noip2016day2解题报告的主要内容,如果未能解决你的问题,请参考以下文章

noip2014Day2解题报告

NOIP2016普及组复赛解题报告

Noip2015day2解题报告

noip2011提高组day1+day2解题报告

$NOIP 2018 Day2$ 模拟考试 题解报告

清北学堂国庆day2解题报告