• NOIP2016:Day2解题报告


    T1 组合数问题:

    = =这道题在考场上的时候还不知道啥是组合数。。。。一看题就觉得哎呀好难啊。。。然而出来之后才听Xorex大神说这道题是杨辉三角???好吧当时实在是太菜了。。。好在写了个分解质因数的算法,原本期望80分的程序,结果我这个小蒟蒻不知道0!=1。。。。。惨啊

    当初的SB代码好像已经没有了

    分析:

      算法一:大力用公式和高精度求组合数,然后每次输入的时候判断一下矩阵内modk的值有几个等于0,输出答案。理想复杂度O(t*m*n),理想情况下的得分是10分

      算法二:在算法一的基础上运用求一下矩阵前缀和,理想复杂度是O(m*n*高精度),得分大概40?

      算法三:用分解因数的方法,判断一下ci,j中是否含有1个或以上的k因子,然后求一下矩阵前缀和,复杂度为O(m*n),理想得分是100分

      算法四:

        数据范围是2000,所以直接用n^2算法递推求出来所有的组合数就行,在求的时候需要mod一下k的值,否则会爆掉精度。

        那么如果ci,j是k的倍数的话,ci,j处的数一定为0,然后我们求一下矩阵的前缀和就行了。复杂度O(m*n),理想得分100分。

     1 //NOIP2017 D2T1
     2 //by:hinanawi
     3 #include<iostream>
     4 #include<cstdio>
     5 #include<cstring>
     6 #include<algorithm>
     7 #include<cctype>
     8 using namespace std;
     9 int n,m,a[2010][2010],sum[2010][2010],k,t;
    10 int read(){
    11     int x=0,y=1;char ch=getchar();
    12     while (!isdigit(ch)){if (ch=='-')y=-1;ch=getchar();}
    13     while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    14     return x*y;
    15 }
    16 int main(){
    17     t=read();k=read();
    18     for (int i=0;i<=2000;i++)
    19         for (int j=0;j<=i;j++){
    20             if (j==0){
    21                 a[i][j]=1%k;
    22             }
    23             else{
    24                 a[i][j]=(a[i-1][j-1]+a[i-1][j])%k;
    25             }
    26         }
    27     if (a[0][0]==0)    sum[0][0]=1;
    28     for (int i=1;i<=2000;i++)
    29         for (int j=0;j<=i;j++){
    30             if (j==0)    sum[i][j]=sum[i-1][j];
    31             else if (i==j)    sum[i][j]=sum[i][j-1];
    32             else sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
    33             if (a[i][j]==0)    ++sum[i][j];
    34         }
    35     while (t--){
    36         n=read();m=read();
    37         printf("%d
    ",sum[n][min(n,m)]);
    38     }
    39     return 0;
    40 }
    算法四

    T2 蚯蚓:

    考场上的时候我连什么是队列都不知道。。。下去之后lzy大神告诉我优先队列可以水60分。。。然后我就用下面的算法一水了35分= =

    分析:

      算法一:最裸的模拟,将所有的蚯蚓长度每次切过之后都加上q,然后再排序一遍。复杂度是O(mnlogn),理想得分35

      算法二:将所有蚯蚓加入一个优先队列中,然后每次全部出队之后加上q,再进队,复杂度同算法一,理想得分35

      算法三:仔细想想其实是不需要将每个蚯蚓出队之后再进队的,开一个结构体,然后记录一下蚯蚓出现的时间及出现时的长度,然后重载一下运算符,就能达到同样的效果,不过重载运算符的操作需要用手写堆来实现,比较麻烦,复杂度为O(mlogn),理想情况下可以拿到80分

      算法四:这个算法需要一个严格的证明:对于最初的蚯蚓来说,当一个蚯蚓比其它的蚯蚓长的话,它永远都比其他蚯蚓长,以及对于切除的蚯蚓ci,cj,i<j来说,其切掉的一条在k(k>j)时刻ci被切成的其中一条蚯蚓ai长度为ci*p+(k-i-1)*q,cj被切成的,与蚯蚓ai系数相同的蚯蚓aj长度为(ci+(j-i)*q)*p+(k-j-1)*q,即ci*p+(j-i)*pq+(k-j-1)*q,很明显ai>aj,这样就证明了蚯蚓的单调性,那么优先队列就没有了意义。所以我们可以开3个队列,第一个队列记录原蚯蚓,第二个队列记录被切成的系数为p的蚯蚓,第三个队列记录系数为1-p的蚯蚓,那么这三个队列都是严格递减的,那么我们每次取蚯蚓的时候讲三个队列的队首进行比较即可。时间复杂度为o(m),理想得分是100。但是!!!这道题输入和输出卡常数。。。需要用快读和快出来进行优化。

     1 //NOIP2016 D2T2
     2 //by:hinanawi
     3 #include<iostream>
     4 #include<cstdio>
     5 #include<cstring>
     6 #include<cctype>
     7 #include<algorithm>
     8 #include<queue>
     9 using namespace std;
    10 int n,m,p,u,v,t,head[4],tail[4],a[100010];
    11 struct node{
    12     int v,t;
    13 }q[4][7500010];
    14 namespace IO{
    15     char buf[1<<15],*fs,*ft;
    16     inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
    17     inline int read(){
    18         int x=0,f=1;  char ch=getc();
    19         while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getc();}
    20         while(isdigit(ch))  {x=x*10+ch-'0';  ch=getc();}
    21         return x*f;
    22     }
    23     void put(int x){
    24         if(x==0){
    25             putchar('0');
    26             return;
    27         }
    28         if(x<0){
    29             putchar('-');
    30             x=-x;
    31         }
    32         int num=0;char ch[16];
    33         while(x) ch[++num]=x%10+'0',x/=10;
    34         while(num) putchar(ch[num--]);
    35     }
    36 };
    37 using namespace IO;
    38 
    39 void init(){
    40     n=read();m=read();p=read();u=read();v=read();t=read();
    41     for (int i=1;i<=n;i++)    a[i]=read();
    42     sort(a+1,a+1+n);
    43     head[1]=1;tail[1]=0;
    44     head[2]=1;tail[2]=0;
    45     head[3]=1;tail[3]=0;
    46     for (int i=n;i>=1;i--){
    47         q[1][++tail[1]].v=a[i];q[1][tail[1]].t=0;
    48     }
    49 }
    50 
    51 void work(){
    52     for (int i=1;i<=m;i++){
    53         int maxx=0,pos=0;
    54         if (head[1]<=tail[1]&&q[1][head[1]].v+(i-q[1][head[1]].t-1)*p>maxx){maxx=q[1][head[1]].v+(i-q[1][head[1]].t-1)*p;pos=1;}
    55         if (head[2]<=tail[2]&&q[2][head[2]].v+(i-q[2][head[2]].t-1)*p>maxx){maxx=q[2][head[2]].v+(i-q[2][head[2]].t-1)*p;pos=2;}
    56         if (head[3]<=tail[3]&&q[3][head[3]].v+(i-q[3][head[3]].t-1)*p>maxx){maxx=q[3][head[3]].v+(i-q[3][head[3]].t-1)*p;pos=3;}
    57         int a1=1LL*maxx*u/v;
    58         int a2=maxx-a1;
    59         head[pos]++;
    60         if (i%t==0){put(maxx);putchar(' ');}
    61         q[2][++tail[2]].v=a1;q[2][tail[2]].t=i;
    62         q[3][++tail[3]].v=a2;q[3][tail[3]].t=i;
    63     }
    64     putchar('
    ');
    65     for (int i=1;i<=m+n;i++){
    66         int maxx=0,pos=0;
    67         if (head[1]<=tail[1]&&q[1][head[1]].v+(m-q[1][head[1]].t)*p>maxx){maxx=q[1][head[1]].v+(m-q[1][head[1]].t)*p;pos=1;}
    68         if (head[2]<=tail[2]&&q[2][head[2]].v+(m-q[2][head[2]].t)*p>maxx){maxx=q[2][head[2]].v+(m-q[2][head[2]].t)*p;pos=2;}
    69         if (head[3]<=tail[3]&&q[3][head[3]].v+(m-q[3][head[3]].t)*p>maxx){maxx=q[3][head[3]].v+(m-q[3][head[3]].t)*p;pos=3;}
    70         head[pos]++;
    71         if (i%t==0){put(maxx);putchar(' ');}
    72     }
    73     putchar('
    ');
    74 }
    75 
    76 int main(){
    77     init();
    78     work();
    79     return 0;
    80 }
    算法四+读入输出优化

    T3 愤怒的小鸟:

    这道题考场上一脸懵逼。。。因为当初什么都不会嘛QAQ

    分析:

      算法一:DFS+回溯,理想分数20-100?

      算法二:我们可以发现DFS的过程是可以记录状态的。所以我们用状态压缩的方式,将所有在以i,j为两个端点的抛物线上的点用二进制的方式记录下来,然后做一遍状压DP就行了。根据DP的方式,分数80-100不等。我用的是类似背包的方法。

     1 //NOIP2016 D2T3
     2 //by:hinanawi
     3 #include<iostream>
     4 #include<cstdio>
     5 #include<cstring>
     6 #include<cctype>
     7 #include<algorithm>
     8 #include<cmath>
     9 using namespace std;
    10 #define eps 0.000001
    11 struct node{
    12     double x,y;
    13 }bird[20];
    14 int T,n,m,flag[20][20],c[10010],tot=0;
    15 double x[20],y[20],a[1<<18],b[1<<18];
    16 int p[20];
    17 int f[1<<18];
    18 int read(){
    19     int x=0,y=1;char ch=getchar();
    20     while (!isdigit(ch)){if (ch=='-')y=-1;ch=getchar();}
    21     while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    22     return x*y;
    23 }
    24 
    25 bool mycmp(node a,node b)
    26 {return a.x<b.x||a.x==b.x&&a.y<b.y;}
    27 
    28 inline void sol(int i,int j){
    29     a[p[i]+p[j]]=(y[j]*x[i]-y[i]*x[j])/((x[j]-x[i])*x[j]*x[i]);
    30     b[p[i]+p[j]]=(y[j]*x[i]*x[i]-y[i]*x[j]*x[j])/((x[i]-x[j])*x[i]*x[j]);
    31 }
    32 
    33 void init(){
    34     memset(f,0x3f,sizeof(f));
    35     memset(flag,0,sizeof(flag));
    36     tot=0;
    37     f[0]=0;
    38     n=read();m=read();
    39     for (int i=1;i<=n;i++)    scanf("%lf%lf",&bird[i].x,&bird[i].y);
    40     sort(bird+1,bird+1+n,mycmp);//不知道为什么这里不排序的话会有一组数据wa掉
    41     for (int i=1;i<=n;i++){
    42         x[i]=bird[i].x;    y[i]=bird[i].y;
    43     }
    44 }
    45 
    46 
    47 
    48 int main(){
    49     T=read();
    50     p[1]=1;
    51     for (int i=2;i<=19;i++)    p[i]=p[i-1]<<1;
    52     while (T--){
    53         init();
    54         for (int i=1;i<=n;i++)
    55             for (int j=i+1;j<=n;j++)    sol(i,j);
    56         for (int i=1;i<=n;i++){
    57             flag[i][i]=p[i];
    58             for (int j=i+1;j<=n;j++){
    59                 if (a[p[i]+p[j]]>=-eps)    continue;
    60                 flag[i][j]=p[i]+p[j];
    61                 f[p[i]+p[j]]=1;
    62                 for (int k=j+1;k<=n;k++){
    63                     if (fabs(a[p[i]+p[j]]-a[p[j]+p[k]])<=eps&&fabs(b[p[i]+p[j]]-b[p[j]+p[k]])<=eps)    flag[i][j]+=p[k];    
    64                     f[flag[i][j]]=1;
    65                 }
    66             }
    67         }
    68         for (int i=1;i<=n;i++)    f[p[i]]=1;
    69         for (int i=1;i<=n;i++)
    70             for (int j=i;j<=n;j++)
    71                 if (flag[i][j]!=0)
    72                     c[++tot]=flag[i][j];
    73         sort(c+1,c+1+tot);
    74         for (int i=1;i<=p[n+1]-1;i++){
    75             if (f[i]!=0x3f3f3f3f)    continue;
    76             for (int j=1;j<=tot&&c[j]<=i;j++){
    77                 if ((c[j]&i)!=c[j])    continue;
    78                 f[i]=min(f[i],f[i-c[j]]+1);
    79             }
    80         }
    81         printf("%d
    ",f[p[n+1]-1]);
    82     }
    83     return 0;
    84 }
    算法二AC代码

     总结:NOIP2016day2还是很常规的一套题,但整体难度要小于day1。偏重考察思维能力,细节方面要小于去年,T1T3在数据范围方面都有点一眼题的意味,期望得分应该在200分以上(100+60+40),然而当初菜的一匹的我只拿了75分。。。(40+35+0)

  • 相关阅读:
    基础数据类型之字符串str
    python编码基础知识
    python逻辑运算之and、or
    Django中消息中间键和form组件的运用
    Django中 cookies and session的使用
    JavaScript 正则制表符,单词边界,去空格
    paramiko堡垒机、线程及锁
    0911 Socket网络编程
    os.system和os.popen
    类高级方法、反射、异常、动态导入模块
  • 原文地址:https://www.cnblogs.com/hinanawitenshi/p/7097481.html
Copyright © 2020-2023  润新知