• NOIP2016总结


    Day1:

    T1:模拟;

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<string>
     6 #include<ctime>
     7 #include<cmath>
     8 #include<set>
     9 #include<map>
    10 #include<queue>
    11 #include<algorithm>
    12 #include<iomanip>
    13 using namespace std;
    14 #define FILE "toy"
    15 #define up(i,j,n) for(int i=(j);i<=(n);i++)
    16 #define pii pair<int,int>
    17 #define LL long long
    18 namespace IO{
    19     char buf[1<<15],*fs,*ft;
    20     int gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?-1:*fs++;}
    21     int read(){
    22         int ch=gc(),f=0,x=0;
    23         while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
    24         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    25         return f?-x:x;
    26     }
    27 }using namespace IO;
    28 const int maxn=101000;
    29 int n,m;
    30 int a[maxn];
    31 char s[maxn][20];
    32 int main(){
    33     freopen(FILE".in","r",stdin);
    34     freopen(FILE".out","w",stdout);
    35     scanf("%d%d",&n,&m);
    36     up(i,0,n-1)scanf("%d %s",&a[i],s[i]);
    37     int x,y,now=0;
    38     up(i,1,m){
    39         scanf("%d%d",&x,&y);
    40         if(x==a[now])now=(now-y+n)%n;
    41         else now=(now+y)%n;
    42     }
    43     printf("%s",s[now]);
    44     return 0;
    45 }
    46  
    View Code

    T2:

    这次noip2016最难的题?

    考场上只急着打暴力了,没有好好思考;

    实际上想了之后还是很简单的;

    这题的关键是理清思路,题目上的特点是 若一条路径已走的时间若与当前节点的值相等,这一点的答案加1;

    最暴力的思路当然是dfs Q遍,先判断这个点是否在这条路径上,然后判断已走的距离是不是等于当前点的权值,都符合的话ans++;

    如何化简条件?

    我们可以发现当若有一条从x->y的路径是一条链,且dep[x]<dep[y],则若dep[i]-dep[x]=v[i],则该点ans++;

    这可以变形成dep[i]-v[i]=dep[x],左边只与点i自身有关;

    经过了这样的转化,我们发现可以这样做,将一个路径拆成从x->lca和lca->y两个链,然后可以仿照上面的方法,用dep与v[i]的关系做。

    但做到了这一步仍然没什么卵用;

    我们是否可以把目光转移,从看一条路径到看每个点?

    对每个点而言,我们需要计算的是,它自身dep[i]±v[i]正好匹配经过它的路径所要求的的值的路径的数目;

    这很绕,实际上对路径只有两个要求,第一个是经过它,第二个是路径与这个点可以匹配;

    怎么维护?

    第一个,维护只经过它的路径的值的集合;

    第二个,在集合中快速找到符合要求的值的数目;

    满足这两个要求,第一个可以用离线的方法维护,第二个可以在dfs的途中顺便维护一个,这个桶里存的就是经过它的路径的值的集合,然后可以O(1)查询;

    这里面还有一个地方需要注意,每次桶从一颗子树出来的时候会带着这颗子树的信息,再进入另一个桶的时候会出现问题,解决方案是作差,先记录一下当前的ans值,待遍历完所有子树,再记录一下当前的ans,两个的差值即为所求;

    在大佬眼里就是道水题...

     

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<string>
      6 #include<ctime>
      7 #include<cmath>
      8 #include<set>
      9 #include<map>
     10 #include<queue>
     11 #include<algorithm>
     12 #include<iomanip>
     13 #include<queue>
     14 using namespace std;
     15 #define FILE "dealing"
     16 #define up(i,j,n) for(int i=(j);i<=(n);i++)
     17 #define pii pair<int,int>
     18 #define LL long long
     19 namespace IO{
     20     char buf[1<<15],*fs,*ft;
     21     int gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?-1:*fs++;}
     22     int read(){
     23         int ch=gc(),f=0,x=0;
     24         while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
     25         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
     26         return f?-x:x;
     27     }
     28 }using namespace IO;
     29 const int maxn=600010;
     30 int n,m;
     31 struct node{
     32     int y,next,v;
     33 }e[maxn],u[maxn],v[maxn],q[maxn];
     34 int headu[maxn],headv[maxn],headq[maxn],lenu,lenv,lenq;
     35 int linkk[maxn],len=0;
     36 int s[maxn],t[maxn],w[maxn];
     37 inline void insert(int x,int y,node* e,int* linkk,int& len,int v){e[++len].y=y;e[len].v=v;e[len].next=linkk[x];linkk[x]=len;}
     38 int top[maxn],siz[maxn],son[maxn],fa[maxn],dep[maxn],Lca[maxn],dfs_clock=0;
     39 int f[maxn],flag[maxn];
     40 int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
     41 int pre[maxn],low[maxn],id[maxn];
     42 void tarjan(int x){
     43     siz[x]=1;
     44     pre[x]=++dfs_clock;
     45     id[dfs_clock]=x;
     46     flag[x]=1;
     47     for(int i=linkk[x];i;i=e[i].next){
     48         if(e[i].y==fa[x])continue;
     49         fa[e[i].y]=x;
     50         dep[e[i].y]=dep[x]+1;
     51         tarjan(e[i].y);
     52     }
     53     for(int i=headq[x];i;i=q[i].next){
     54         if(Lca[q[i].v])continue;
     55         if(flag[q[i].y]==1)Lca[q[i].v]=q[i].y;
     56         else if(flag[q[i].y]==2)Lca[q[i].v]=getf(q[i].y);
     57     }
     58     f[x]=fa[x];
     59     flag[x]=2;
     60     low[x]=++dfs_clock;
     61     id[dfs_clock]=x;
     62 }
     63 void init(){
     64     n=read(),m=read();
     65     int x,y;
     66     up(i,1,n-1){x=read(),y=read();insert(x,y,e,linkk,len,0);insert(y,x,e,linkk,len,0);}
     67     up(i,1,n)w[i]=read();
     68     up(i,1,m){
     69         s[i]=read(),t[i]=read();
     70         insert(s[i],t[i],q,headq,lenq,i);
     71         insert(t[i],s[i],q,headq,lenq,i);
     72     }
     73     up(i,1,n)f[i]=i;
     74     tarjan(1);
     75 }
     76 inline void make_tag(int s,int t,int st,bool flag){
     77     if(flag){
     78         insert(s,st,u,headu,lenu,1);
     79         insert(t,st,u,headu,lenu,-1);
     80     }
     81     else {
     82         insert(s,st,v,headv,lenv,1);
     83         insert(t,st,v,headv,lenv,-1);
     84     }
     85 }
     86 int ans[maxn];
     87 int cnt1[maxn<<3],cnt2[maxn<<3];
     88 int l[maxn];
     89 void slove(){
     90     up(i,1,m){
     91         if(Lca[i]==s[i])make_tag(fa[s[i]],t[i],dep[s[i]],0);
     92         else if(Lca[i]==t[i])make_tag(s[i],fa[t[i]],dep[s[i]],1);
     93         else {
     94             make_tag(s[i],fa[Lca[i]],dep[s[i]],1);
     95             make_tag(Lca[i],t[i],2*dep[Lca[i]]-dep[s[i]],0);
     96         }
     97     }
     98     memset(flag,0,sizeof(flag));
     99     int x;
    100     for(int i=1;i<=dfs_clock;i++){
    101         x=id[i];
    102         if(flag[x]){
    103             for(int i=headu[x];i;i=u[i].next){
    104                 if(u[i].v==-1)cnt1[u[i].y+maxn]--;
    105                 else cnt1[u[i].y+maxn]++;
    106             }
    107             for(int i=headv[x];i;i=v[i].next){
    108                 if(v[i].v==1)cnt2[v[i].y+maxn]--;
    109                 else cnt2[v[i].y+maxn]++;
    110             }
    111             ans[x]=cnt1[dep[x]+w[x]+maxn]+cnt2[dep[x]-w[x]+maxn]-l[x];
    112         }
    113         else {
    114             l[x]=cnt1[dep[x]+w[x]+maxn]+cnt2[dep[x]-w[x]+maxn];
    115             flag[x]=1;
    116         }
    117     }
    118     up(i,1,n)printf("%d%c",ans[i],i==n?'
    ':' ');
    119 }
    120 int main(){
    121     freopen(FILE".in","r",stdin);
    122     freopen(FILE".out","w",stdout);
    123     init();
    124     slove();
    125     return 0;
    126 }
    View Code

     

    顺便进行了一下求lca的速度测试:

    只求LCA的话,树链剖分最快,tarjan次之,倍增最慢(经常被卡);

    还需要一些附加信息的话,tarjan无法处理,树链剖分效率很好,倍增效率太低;

    代码长度上,树链剖分最长,lca次之,tarjan最短;

    如果考场上只求lca的话,建议tarjan,很好写;

    T3:

    无力吐槽,这题让一心一意备考noip的人怎么受得了;

    概率dp;

    把概率扒下来其实就是一背包动规;

    具体的还是自己去体会(看代码)......

     

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<string>
     6 #include<ctime>
     7 #include<cmath>
     8 #include<set>
     9 #include<map>
    10 #include<queue>
    11 #include<algorithm>
    12 #include<iomanip>
    13 #include<queue>
    14 using namespace std;
    15 #define FILE "dealing"
    16 #define up(i,j,n) for(int i=(j);i<=(n);i++)
    17 #define pii pair<int,int>
    18 #define LL long long
    19 #define db double 
    20 namespace IO{
    21     char buf[1<<15],*fs,*ft;
    22     int gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?-1:*fs++;}
    23     int read(){
    24         int ch=gc(),f=0,x=0;
    25         while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
    26         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    27         return f?-x:x;
    28     }
    29 }using namespace IO;
    30 const int maxn=2020;
    31 const db inf=100000000.0;
    32 int n,m,v,e,a[maxn],b[maxn];
    33 db k[maxn];
    34 int d[maxn][maxn];
    35 void init(){
    36     scanf("%d%d%d%d",&n,&m,&v,&e);
    37     memset(d,10,sizeof(d));
    38     up(i,1,v)d[i][i]=0;
    39     up(i,1,n)scanf("%d",&a[i]);
    40     up(i,1,n)scanf("%d",&b[i]);
    41     up(i,1,n)scanf("%lf",&k[i]);
    42     int x,y,vv;
    43     up(i,1,e){
    44         scanf("%d%d%d",&x,&y,&vv);
    45         if(d[x][y]>vv)d[x][y]=d[y][x]=vv;
    46     }
    47     up(g,1,v)up(i,1,v)up(j,1,v)if(d[i][g]+d[g][j]<d[i][j])d[i][j]=d[i][g]+d[g][j];
    48 }
    49 db f[2020][2020][2];
    50 void slove(){
    51     up(i,1,n)up(j,0,m)f[i][j][0]=f[i][j][1]=inf;
    52     f[1][1][1]=f[1][0][0]=0;
    53     db duu,duv,dvu,dvv,ans=inf;
    54     up(i,2,n)for(int j=0;j<=i&&j<=m;j++){
    55         duu=d[a[i-1]][a[i]],duv=d[a[i-1]][b[i]],dvu=d[b[i-1]][a[i]],dvv=d[b[i-1]][b[i]];
    56         if(j!=i)f[i][j][0]=min(f[i-1][j][1]+duu*(1-k[i-1])+dvu*k[i-1],duu+f[i-1][j][0]);
    57         if(j)f[i][j][1]=min(f[i-1][j-1][1]+duu*(1-k[i-1])*(1-k[i])+duv*(1-k[i-1])*k[i]+dvv*k[i]*k[i-1]+dvu*k[i-1]*(1-k[i]),f[i-1][j-1][0]+duv*k[i]+duu*(1-k[i]));
    58     }
    59     for(int i=0;i<=m;i++)ans=min(ans,min(f[n][i][0],f[n][i][1]));
    60     printf("%.2lf
    ",ans);
    61 }
    62 int main(){
    63     freopen(FILE".in","r",stdin);
    64     freopen(FILE".out","w",stdout);
    65     init();
    66     slove();
    67     return 0;
    68 }
    View Code

     

     

    Day2:

    T1:

    组合数,考场脑子一抽写了二维树状数组,但实际也没什么问题(实际这题的二维动规是有一定的风险的,有人因此挂了);

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<string>
     6 #include<ctime>
     7 #include<cmath>
     8 #include<set>
     9 #include<map>
    10 #include<queue>
    11 #include<algorithm>
    12 #include<iomanip>
    13 using namespace std;
    14 #define FILE "problem"
    15 #define up(i,j,n) for(int i=(j);i<=(n);i++)
    16 #define pii pair<int,int>
    17 #define LL long long
    18 namespace IO{
    19     char buf[1<<15],*fs,*ft;
    20     int gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?-1:*fs++;}
    21     int read(){
    22         int ch=gc(),f=0,x=0;
    23         while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
    24         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    25         return f?-x:x;
    26     }
    27 }using namespace IO;
    28 const int maxn=2020,N=2000;
    29 int c[maxn][maxn];
    30 int sum[maxn][maxn];
    31 int T,k,n,m;
    32 int main(){
    33     //freopen(FILE".in","r",stdin);
    34     //freopen(FILE".out","w",stdout);
    35     T=read(),k=read();
    36     c[0][0]=1;
    37     up(i,1,N){
    38         c[i][0]=1;
    39         up(j,1,i){
    40             c[i][j]=(c[i-1][j-1]+c[i-1][j])%k;
    41             sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+(c[i][j]==0?1:0);
    42         }
    43         up(j,i+1,N)sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
    44     }
    45     while(T--){
    46         n=read(),m=read();
    47         if(m>n)m=n;
    48         printf("%d
    ",sum[n][m]);
    49     }
    50     return 0;
    51 }
    View Code

    T2:

    数学题目,需要证一下单调性(求个导如何?)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<string>
     6 #include<ctime>
     7 #include<cmath>
     8 #include<set>
     9 #include<map>
    10 #include<queue>
    11 #include<algorithm>
    12 #include<iomanip>
    13 using namespace std;
    14 #define FILE "earthworm"
    15 #define up(i,j,n) for(int i=(j);i<=(n);i++)
    16 #define pii pair<int,int>
    17 #define LL long long
    18 namespace IO{
    19     char buf[1<<15],*fs,*ft;
    20     int gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?-1:*fs++;}
    21     int read(){
    22         int ch=gc(),f=0,x=0;
    23         while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
    24         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    25         return f?-x:x;
    26     }
    27 }using namespace IO;
    28 const int maxn=8001000;
    29 const double E=0.0000001;
    30 int a[maxn],b[maxn],c[maxn];
    31 int ha,hb,hc,tb=1,tc=1;
    32 int n,m,u,v,t,q,d;
    33 LL pop(){
    34     int L;
    35     if(ha&&(a[ha]>=b[tb]||tb>hb)&&(a[ha]>=c[tc]||tc>hc))L=a[ha],ha--;
    36     else if(tb<=hb&&(b[tb]>=a[ha]||!ha)&&(b[tb]>=c[tc]||tc>hc))L=b[tb],tb++;
    37     else L=c[tc],tc++;
    38     return L;
    39 }
    40 int main(){
    41     n=read(),m=read(),q=read(),u=read(),v=read(),t=read();
    42     up(i,1,n)a[i]=read();
    43     sort(a+1,a+n+1);
    44     ha=n;
    45     LL L,top=1;
    46     up(i,1,m){
    47         L=pop()+d;
    48         d+=q;
    49         if(top*t==i){printf("%lld ",L);top++;}
    50         b[++hb]=(int)(L*u/v)-d;
    51         c[++hc]=L-b[hb]-2*d;
    52     }
    53     cout<<endl;
    54     top=1;
    55     up(i,1,m+n){
    56         L=pop();
    57         if(t*top==i){printf("%lld ",L+d);top++;}
    58     }
    59     return 0;
    60 }
    61  
    View Code

    T3:

    惭愧惭愧,考场不假思索,先打暴力......

    后改记忆化,本质上都是状压dp;

    吐槽的是,我同学写正解都被卡了一个n,而我写dfs,没有被卡掉......

    实质上dfs会避免访问很多不可能出现的状态,所以效率比较高;

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<string>
     6 #include<ctime>
     7 #include<cmath>
     8 #include<set>
     9 #include<map>
    10 #include<queue>
    11 #include<algorithm>
    12 #include<iomanip>
    13 using namespace std;
    14 #define FILE "angrybirds"
    15 #define up(i,j,n) for(int i=(j);i<=(n);i++)
    16 #define pii pair<int,int>
    17 #define LL long long
    18 #define pdd pair<double,double> 
    19 namespace IO{
    20     char buf[1<<15],*fs,*ft;
    21     int gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?-1:*fs++;}
    22     int read(){
    23         int ch=gc(),f=0,x=0;
    24         while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
    25         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
    26         return f?-x:x;
    27     }
    28 }using namespace IO;
    29 inline bool chkmin(int &a,int b){return a>b?a=b,true:false;}
    30 inline bool chkmax(int &a,int b){return a<b?a=b,true:false;}
    31 const int maxn=20,N=2000;
    32 const double E=0.00000001;
    33 int T,n,m;
    34 int ans;
    35 double x[maxn],y[maxn];
    36 inline bool c(double x,double y){return abs(x-y)<=E;} 
    37 inline pdd slove(double q,double w,double e,double r){
    38     pdd dui;
    39     if(c(q,e))return make_pair(0,0);
    40     dui.first=(w*e-q*r)/(q*e*(q-e));
    41     if(dui.first+E>=0)return make_pair(0,0);
    42     dui.second=(w*e-dui.first*q*q*e)/(q*e);
    43     return dui;
    44 }
    45 int f[300000];
    46 int dfs(int top,int vis){
    47     if(f[vis]!=-1)return f[vis];
    48     if(top==n+1)return f[vis]=0;
    49     if((1<<top-1)&vis)return f[vis]=dfs(top+1,vis);
    50     pdd p;
    51     f[vis]=n;
    52     int q=vis;
    53     up(i,top+1,n){
    54         vis=q;
    55         if(!((1<<i-1)&vis)){
    56             p=slove(x[top],y[top],x[i],y[i]);
    57             if(!p.first)continue;
    58             vis=vis^(1<<top-1);
    59             vis=vis^(1<<i-1);
    60             up(j,top+1,n){
    61                 if(vis&(1<<j-1))continue;
    62                 if(c(p.first*x[j]*x[j]+p.second*x[j],y[j]))vis=vis^(1<<j-1);
    63             }
    64             chkmin(f[q],dfs(top+1,vis)+1);
    65         }
    66     }
    67     vis=q;
    68     chkmin(f[vis],dfs(top+1,vis^(1<<top-1))+1);
    69     return f[vis];
    70 }
    71 int main(){
    72     //freopen(FILE".in","r",stdin);
    73     //freopen(FILE".out","w",stdout);
    74     scanf("%d",&T);
    75     while(T--){
    76         scanf("%d%d",&n,&m);
    77         up(i,1,n)scanf("%lf%lf",&x[i],&y[i]);
    78         if(!m||m==2)ans=n;
    79         if(m==1)ans=(n%3)?(n/3+2):(n/3+1);
    80         memset(f,-1,sizeof(f));
    81         cout<<dfs(1,0)<<endl;
    82     }
    83     return 0;
    84 }
    View Code

     

  • 相关阅读:
    他山之石____集合框架__【List,Set,Map之间的区别】
    集合框架__【泛型】
    集合框架__【Set集合】【HashSet】【TreeSet】
    模式串匹配,KMP算法——HDU1686
    模式串匹配,KMP算法——HDU1711
    网络最大流——POJ
    网络最大流——HDU
    拓扑排序——CodeForces-645D
    二分图染色,二分图匹配——HDU
    二分图匹配,最小点覆盖——POJ
  • 原文地址:https://www.cnblogs.com/chadinblog/p/6123797.html
Copyright © 2020-2023  润新知