2016.7.18 NOIP2014提高组day1解题报告

乌鸦嘴如我......果然考差了,直接原因是第二题审错题,当然,深层原因绝不会这么简单。不知道自己花在解题报告上的时间是否有意义,毕竟这些时间本可以改好几道题出来,的确要反思一下。

考试分析:

1.做题习惯不好,不能只观察数据,要结合题给其他条件,站在逻辑的高度。这次审错题个人觉得很经典:把特殊的树当成了链来做,这显然是没有顾全大局的,说明在思考时未能抹去之前错误的认识,完全没有思考解题方法的正确性,还是太急了,要学会反向思考;

2.实现代码太慢,完全没有时间思考第三道题,本来按照思路应该很容易发现动规比深搜快很多的,但却担心来不及写放弃了,要多刷题;

3.花在废话上时间太多,写结题报告显然比调程序简单一点,所以我会花大量的时间来写解题报告,本来总结归纳也是很有用的,但是现在时间不够,找到弱点也没时间落实,不如跟好老师的步伐,尤其是在解题报告里废话少一点;

题目分析:

一.生活大爆炸版石头剪刀布

题意:NCAC题;

题目分析:技巧关键词:取余,对称,直接加分;

代码:

    #include<cstdio>

#include<iostream>

#include<cmath>

#include<cstdlib>

#include<cstring>

#include<string>

#include<algorithm>

#include<queue>

#include<set>

using namespace std;

int n,na,nb,a[205],b[205],stua,stub;

int ovo[5][5]={{0,0,1,1,0},{1,0,0,1,0},{0,1,0,0,1},{0,0,1,0,1},{1,1,0,0,0}};

int main()

{

         freopen("rps.in","r",stdin);

         freopen("rps.out","w",stdout);

         scanf("%d %d %d",&n,&na,&nb);

         for(int i=0;i<=na-1;i++)

         scanf("%d",&a[i]);

         for(int j=0;j<=nb-1;j++)

         scanf("%d",&b[j]);

         for(int i=0;i<=n-1;i++)

         {

                   stua+=ovo[a[i%na]][b[i%nb]];

                   stub+=ovo[b[i%nb]][a[i%na]];

         }

         printf("%d %d",stua,stub);

         return 0;

}

二.联合权值

题意:隔一点的树:n 200 000 w 10 000;

题目分析:

    根据题意很容易发现任意两点仅一条路径,发现这条性质以后把图画出来会发现,每次求的就是任意两个子节点的乘积,(树)(仅一个前驱)然后好笑的事情发生了:我把图一画——链嘛,然后编了很久,自以为拿了一百,结果......呵呵(手动微笑)所以拿到题目以后先自己画一个图,再分析样例,并且自己的图一定要是最具一般性的!再想计算时的简化(比如直接找儿子),当然大神提供的一个式子为100%提供了可能,不太好打,可以看程序理解。顺便,longlong运算要比int慢很多,写这种多过一组是一组的程序,一定要能简化的地方都简化!;

(链的愚蠢程序)   

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;
const int MAXN=200005,m=10007;
int sta[MAXN],fin[MAXN],n,w[MAXN],used[MAXN],inf[MAXN][2],flg,maxn,tot,flg2;
struct pie
{
    int rig,lef;
}lace[MAXN];
void cre(int k,int dot,int las)
{    
    used[k]=1;
    lace[k].lef=las;
    lace[las].rig=k;
    int k1=inf[dot][0]+inf[dot][1]-k;
    int dot1=fin[k1]+sta[k1]-dot;        
    if(k1==0){flg2=dot;lace[k].rig=-1;return;}
    cre(k1,dot1,k);
}
void res(int dot,int k,int las)
{
    maxn=max(maxn,w[las]*w[dot]);
    tot+=(w[las]%m)*(w[dot]%m)%m;
    tot%=m;
    if(lace[k].rig==-1)return;
    int k1=lace[k].rig;
    int dot1=fin[k1]+sta[k1]-dot;
    int las1=fin[k]+sta[k]-dot; 
    res(dot1,k1,las1);
}
void init()
{
    scanf("%d",&n);
    for(int i=1;i<=n-1;i++)
    {
    scanf("%d %d",&sta[i],&fin[i]);
    if(inf[sta[i]][0])inf[sta[i]][1]=i;
    else inf[sta[i]][0]=i;
    if(inf[fin[i]][0])inf[fin[i]][1]=i;
    else inf[fin[i]][0]=i;
    }
    for(int i=1;i<=n;i++)
    scanf("%d",&w[i]);
    for(int i=1;i<=n;i++)
    if(!inf[i][1])
    {flg=i;break;}
    int k3=inf[flg][0];
    lace[k3].lef=-1;
    used[k3]=1;
    int dot=sta[k3]+fin[k3]-flg;
    int k2=inf[dot][0]+inf[dot][1]-k3;
    int dot1=fin[k2]+sta[k2]-dot;
    if(k2==0){
    flg2=dot;lace[k3].rig=-1;}
    else  cre(k2,dot1,k3);
}
int main()
{
    freopen("link.in","r",stdin);
    freopen("link.out","w",stdout);
    init();
    int k1=inf[flg][0];
    int k2=lace[k1].rig;
    if(k2!=-1)
    {
    int dot=fin[k2]+sta[k2]-fin[k1]-sta[k1]+flg;
    res(dot,k1,flg);
    }
    printf("%d %d",maxn,(tot*2)%m);
    return 0;
}

100%的程序

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;
const int MAXN=200005,m=10007;
int maxn,tot,sta,fin,n,w[MAXN],a[MAXN],b[MAXN],c,d,ans;
struct TREE
{
    int f,dot,nex;
}lace[2*MAXN];
int main()
{
    freopen("link.in","r",stdin);
    freopen("link.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n-1;i++)
    {
    scanf("%d %d",&sta,&fin);
    lace[2*i-1].f=sta;lace[2*i-1].dot=fin;lace[2*i-1].nex=a[sta];a[sta]=2*i-1;
    lace[2*i].f=fin;lace[2*i].dot=sta;lace[2*i].nex=a[fin];a[fin]=2*i;
    }
    for(int i=1;i<=n;i++)
    {scanf("%d",&w[i]);}
    for(int i=1;i<=n;i++)
    {int j=a[i];tot=0;c=0;d=0;
    while(lace[j].nex)
    {
        tot++;b[tot]=w[lace[j].dot];
        c+=((b[tot]%m)*(b[tot]%m))%m;d+=b[tot]%m;
        c%=m;d%=m;
        j=lace[j].nex;
    }
    tot++;b[tot]=w[lace[j].dot];
    c+=((b[tot]%m)*(b[tot]%m))%m;d+=b[tot]%m;
    c%=m;d%=m;d*=d;d%=m;
    sort(b+1,b+tot+1);
    ans+=(d-c+m)%m;ans%=m;
    maxn=max(maxn,b[tot]*b[tot-1]);
    }
    printf("%d %d",maxn,ans);
    return 0;
}
(这里是不需要除以二的,模后除和除后模因为是int都会出问题,所以只能:1.用逆元;2.观察;)

三.飞扬的小鸟

题意:越过障碍,模拟+动规;(要把每个情况对应时间还是时刻弄清楚)

题目分析:发现x,y可以表示状态后我就打算动规,但想一想x*y时间复杂度好高啊(愚蠢),而且时间又不够就放弃了呵呵(手动微笑),所以实现代码一定要快,为最后一道题留够充足时间,你不会只想要200吧;

    这里加了一个优化,直接动规只能70%,但因为你可以从自己推上来,所以你重复计算了很多值,这种重复剪的思维很重要(大神是从背包想出来的,666)

原文地址:https://www.cnblogs.com/SindarDawn/p/5683663.html