Noip2014day1解题报告

Posted

tags:

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

Noip2014day1解题报告

张炳琪

一.时间分配

T1:20分钟

T2:60分钟

T3:130分钟

二.答题情况和错因

T1:100  T2:100  T3:75  TOT 275

T1:一个比较简单的模拟题,用常量数组会看起来不那么乱

T2:刚开始考虑dp后来发现在dfs第二次的时候并不需要dp所以遍历一遍输出就能得到答案了

T3:dp的转移方法不对会超时,背包转移写的不对不敢写

三.题目解析

T1:常量数组表示胜负,其余的就是循环模拟了

T2:应该是类似于树形dp的一个题目先转有根树,维护孩子最大值和孩子的权值总和

dfsdp分为两种情况,第一种是和孙子形成有序数对,这时候就用上刚才维护的东西了   相乘即可

另一种是儿子和儿子形成有序数对  这个我想不到什么好办法,只能求个前缀和啥的乱搞  不过理论复杂度依旧是O(n)的,不过常数略大

注意所有的计算都是单向的,所以说最后要乘以二

T3:一个以前做过的背包问题,忘记背包具体怎么写了  就乱搞一下吧

dp[i][j] 表示到了第i个位置高度为j的最小步数,tal[i]表示改点点击的话上飞的高度

down[i]表示不点击的话下降的高度 然后考虑向dp[i + 1][x]转移可以考虑的是上升的话次数无限,则枚举点击的次数 向dp[i + 1][j + tal[i] * 点击次数]转移下降的话不需要点击 向dp[i + 1][j - down[i]]转移 考虑一下有柱子的地方不转移  转移飞到上界之外的情况

正解是背包,原理是利用完全背包的那个dp方式,减少时间复杂度

四.代码

T1:

#include<cstdio>
#include<algorithm>
#include<iostream>
#define MAXN 2010
using namespace std;

const int mp[5][5] = {
0,1,2,2,1,
2,0,1,2,1,
1,2,0,1,2,
1,1,2,0,2,
2,2,1,1,0
};
int notea[MAXN];int noteb[MAXN];
int ansa = 0,ansb = 0;
int n,na,nb,cnta,cntb;
int main()
{
    //freopen("rps.in","r",stdin);freopen("rps.out","w",stdout);
    scanf("%d%d%d",&n,&na,&nb);
    for(int i = 1;i <= na;i++)scanf("%d",&notea[i]);
    for(int i = 1;i <= nb;i++)scanf("%d",&noteb[i]);
    cnta = 1;cntb = 1;
    for(int i = 1;i <= n;i++)
    {
        int op = mp[notea[cnta]][noteb[cntb]];
        if(op == 1)ansb++;
        if(op == 2)ansa++;
        cnta++;cntb++;
        if(cnta == na + 1)cnta = 1;
        if(cntb == nb + 1)cntb = 1;
    }
    printf("%d %d",ansa,ansb);
    return 0;
}

T2:

#include<cstdio>
#include<algorithm>
#include<iostream>
#define MAXN 200100
const int mod = 10007;
using namespace std;
struct Edge {
    int vi;
    int vj;
    int next;
} edge[MAXN << 1];

int wei[MAXN];//点权
int sum_[MAXN]; //儿子和
int maxx[MAXN];//最大儿子
int stack[MAXN],top;//递归内储存儿子的
int head[MAXN],now = 0;
int SUM[MAXN];//递归内前缀和
int note[MAXN];//最后答案 
int n,ans = 0;
void push(int vi,int vj) {
    now++;
    edge[now].vi = vi;
    edge[now].vj = vj;
    edge[now].next = head[vi];
    head[vi] = now;
}

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

void dfs(int noww,int fa)
{
    for(int i = head[noww];i;i = edge[i].next)
    {
        int vj = edge[i].vj;
        if(vj == fa)continue;
        sum_[noww] += wei[vj];
        maxx[noww] = max(maxx[noww],wei[vj]);
        dfs(vj,noww);
    }
    sum_[noww] %= mod;
}

void dp(int noww,int fa)
{
    for(int i = head[noww];i;i = edge[i].next)//和孙子配对 
    {
        int vj = edge[i].vj;
        if(vj == fa)continue;
        note[noww] += sum_[vj] * wei[noww];
        note[noww] %= mod;
        ans = max(ans,maxx[vj] * wei[noww]);
        dp(vj,noww);
    }
    top = 0; // 重置计数器 
    int op = 0;//寻找次大 
    bool flag = false;
    for(int i = head[noww];i;i = edge[i].next)
    {
        int vj = edge[i].vj;
        if(vj == fa)continue;
        if(wei[vj] >= op)
        {
            if(flag)op = wei[vj];
            else 
            if(wei[vj] == maxx[noww])
            {
                flag = true;
            }
            else op = wei[vj];
         } 
        stack[++top] = wei[vj];
        SUM[top] = SUM[top- 1] + wei[vj];
        SUM[top] %= mod;
    }
    ans = max(ans,op * maxx[noww]);
    
    for(int i = top;i > 1;i--)
    {
        note[noww] += stack[i] * SUM[i - 1];
        note[noww] %= mod;
    }
}

int main() {
    //freopen("link.in","r",stdin);freopen("link.out","w",stdout);
    n = read();
    for(int i = 1;i < n;i++)
    {
        int vi = read(),vj = read();
        push(vi,vj);
        push(vj,vi);
    }
    for(int i = 1;i <= n;i++)
        wei[i] = read();
    dfs(1,0);
    dp(1,0);
    int op = 0;
    for(int i = 1;i <= n;i++)
    {
        op += note[i];
        if(op >= mod)op -= mod;
    }
    op = op * 2 % mod;
    printf("%d %d",ans,op);
    return 0;
}

T3:

#include<cstdio>
#include<cstring>
#define MAXN 10010
using namespace std;
int dp[MAXN][1010];
int tal[MAXN];
int don[MAXN];
bool zhu[MAXN];int up[MAXN];int low[MAXN];//储存柱子的数据
int tot = 0;
int n,m,k;
int read()
{
    int nm = 0;
    char c = getchar();
    while(c > 9 || c < 0)c = getchar();
    while(c <= 9 && c >= 0)
    {
        nm *= 10;
        nm += c - 0;
        c = getchar();
    }
    return nm;
}

int min(int x,int y)
{
    return x < y ? x : y;
}
int max(int x,int y)
{
    return x > y ? x : y;
}

void debug(int x)
{
    for(int i = 1;i <= m;i++)
    {
        int op = dp[x][i];
        if(op == 1044266558)op = 1000;
        printf("%d ",op);
    }
    printf("\n");
}

int main()
{
    //freopen("bird.in","r",stdin);freopen("bird.out","w",stdout);
    memset(dp,0x3e,sizeof(dp));
    n = read();m = read();k = read();
    for(int i = 0;i < n;i++)
    {
        tal[i] = read();
        don[i] = read();
    }
    for(int i = 1;i <= m;i++)
        dp[0][i] = 0;
    for(int i = 1;i <= k;i++)
    {
        int op = read();
        zhu[op] = true;
        low[op] = read();
        up[op] = read();
    }
    for(int i = 0;i <= n;i++)
    {
        if(!zhu[i])up[i] = m + 1;
    }
    for(int i = 0;i <= n;i++)
    {
        bool flag = false;
        for(int j = low[i] + 1;j <= up[i] - 1;j++)
        {
            if(dp[i][j] == 1044266558)continue;
            flag = true;
            int zz;
            if(low[i + 1] > j)
                zz = (low[i + 1] - j) / tal[i];
            else zz = 1;
            int op = j + tal[i] * zz;
            while(op < up[i + 1]) // 这里刚开始写错了 
            {
                if(op > low[i + 1])
                {
                    //dp[i + 1][op] = min(dp[i + 1][op],dp[i][j] + zz);
                    if(dp[i + 1][op] > dp[i][j] + zz)
                        dp[i + 1][op] = dp[i][j] + zz;
                    else
                        break;
                }
                op += tal[i];
                zz++;
            }
            if(!zhu[i + 1] && op > m)dp[i + 1][m] = min(dp[i + 1][m],dp[i][j] + zz);
            op = j - don[i];
            if(op > low[i + 1] && op < up[i + 1])// 
            dp[i + 1][op] = min(dp[i][j],dp[i + 1][op]);        
        }
        if(!flag)
        {
            printf("0\n%d",tot);
            return 0;
        }
        if(zhu[i])tot++;
        //debug(i + 1);
    }
    int cns = 0x7fffffff;
    for(int i = 1;i <= m;i++)
    {
        cns = min(cns,dp[n][i]);
    }
    printf("1\n%d",cns);
    return 0;
}

 

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

noip2011提高组day1+day2解题报告

noip2013day1解题报告

NOIP2015 解题报告

NOIP2016普及组复赛解题报告

noip2014Day2解题报告

noip2014解方程解题报告