• 【NOIP2016TG】solution


    传送门:https://www.luogu.org/problem/lists?name=&orderitem=pid&tag=83%7C33

    D1T1(toys)

    题意:有n个小人,给你M条指令,每条指令可顺可逆(时针),问你操作后的位置在哪。

    解题思路:裸模拟即可。

    #include<stdio.h>
    using namespace std;
    #define MN 100005
    char a[MN][15];
    int n,m;
    bool b[MN];
    inline int in(){
        int x=0;char ch=getchar();
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x;
    }
    int main(){
        n=in();m=in();
        for (int i=1; i<n; ++i){b[i]=in();scanf("%s",a[i]);}
        b[0]=in();scanf("%s",a[0]);
        int nt=1;
        for(int i=1; i<=m; ++i){
            int x=(in()^b[nt])?1:-1,k=in();nt+=k*x;
            if (nt<0) nt+=2*n;nt%=n;
        }
        puts(a[nt]);
    }

    D1T2(running)

    大丧题,解题思路已经存在博客中了,这里放一下传送门,顺便贴个代码。

    传送门:http://www.cnblogs.com/Melacau/p/NOIP2016_running.html

    贴代码:

    #include<stdio.h>
    #define MN 300005
    #define nt edge[i].to
    struct zxy{int to,next;}edge[MN*8];//链表(把多个链表都塞进去了)
    int cnt,h[MN],q[MN],adh1[MN],deh1[MN],adh2[MN],deh2[MN];//各链表表头
    int qans[MN],tim[MN],deep[MN],n,m,chafen[MN*3],fa[MN],ans[MN],x[MN],y[MN];
    bool vis[MN];
    inline void ins(int *h,int x,int y){edge[++cnt].next=h[x],edge[cnt].to=y,h[x]=cnt;}//构造链表
    inline int getfa(int x){return fa[x]?fa[x]=getfa(fa[x]):x;}//并查集
    inline int in(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    inline void tjlca(int x,int d){
        deep[x]=d;vis[x]=1;
        for (register int i=h[x]; i; i=edge[i].next) 
            if (!vis[nt])tjlca(nt,d+1),fa[nt]=x;
        for (register int i=q[x]; i; i=edge[i].next)
            if (qans[nt]) qans[nt]=getfa(qans[nt]);
            else qans[nt]=x;
    }//tarjan算法求LCA
    inline void dfs1(int u){
        vis[u]=0;ans[u]-=chafen[deep[u]-tim[u]];
        for (register int i=h[u]; i; i=edge[i].next) if (vis[nt]) dfs1(nt);
        for (register int i=adh1[u]; i; i=edge[i].next) ++chafen[nt];
        ans[u]+=chafen[deep[u]-tim[u]];
        for (register int i=deh1[u]; i; i=edge[i].next) --chafen[nt];
    }//dfs处理S->f的
    inline void dfs2(int u){
        vis[u]=1;ans[u]-=chafen[deep[u]+tim[u]];
        for (register int i=h[u]; i; i=edge[i].next) if (!vis[nt]) dfs2(nt);
        for (register int i=adh2[u]; i; i=edge[i].next) ++chafen[nt];
        ans[u]+=chafen[deep[u]+tim[u]];
        for (register int i=deh2[u]; i; i=edge[i].next) --chafen[nt];
    }//dfs处理f->T的
    void read(){
        n=in(),m=in();int u,v;
        for (int i=1; i<n; ++i) u=in(),v=in(),ins(h,u,v),ins(h,v,u);
        for (register int i=1; i<=n; ++i) tim[i]=in()-MN;//为了防止减法出现负数,所以我们要这么做。
        for (register int i=1; i<=m; ++i) x[i]=in(),y[i]=in(),ins(q,x[i],i),ins(q,y[i],i);
    }//输入
    void init(){
        tjlca(1,0);
        for (register int i=1; i<=m; ++i){
            int f=qans[i],u=x[i],v=y[i];
            if (f==v) ins(adh2,u,deep[u]+MN),ins(deh2,v,deep[u]+MN);
            else{
                if (f==u) ins(adh1,v,deep[u]+MN),ins(deh1,u,deep[u]+MN);
                else{
                    ins(adh2,u,deep[u]+MN);
                    ins(deh2,f,deep[u]+MN);
                    ins(adh1,v,(deep[f]<<1)-deep[u]+MN);
                    ins(deh1,f,(deep[f]<<1)-deep[u]+MN);
                    if(deep[f]==deep[u]-tim[f]-MN) --ans[f];        
                }
            }
        }
    }//处理差分位置
    void solve(){
        dfs1(1);//进行第一次遍历统计答案
        for (register int i=1; i<=n; ++i) tim[i]+=MN<<1;//这个处理很关键!
        dfs2(1);
        for (register int i=1; i<n; ++i) printf("%d ",ans[i]); printf("%d",ans[n]);
    }
    int main(){
        read();
        init();
        solve();
    }

    D1T3(classroom)

    题意:给你V个点,你一共要执行N个阶段,每个阶段可能在任意2个点上进行,不同点的概率不同,求执行完所有阶段的期望。

    解题思路:floyd预处理最短路,然后跑期望DP。(注意精度控制)

    #include <stdio.h>
    #include <string.h>
    #define min(a,b) (a<b?a:b)
    #define inf 1e9
    #define MN 2001
    #define MV 301
    using namespace std;
    int n,m,v,e,cnt,dis[MV][MV],c[MN],d[MN];
    double qw[MN],ans=inf,f[MN][MN][2];
    inline int in(){
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9') f=c=='-'?-1:1,c=getchar();
        while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
        return x*f;
    }
    void init(){
        n=in(),m=in(),v=in(),e=in();
        for (int i=1; i<=n; ++i) c[i]=in();
        for (register int i=1; i<=n; ++i) d[i]=in();
        for (register int i=1; i<=n; ++i) scanf("%lf",&qw[i]);
        for(register int i=1; i<=v; ++i)
            for(int j=1; j<=v; ++j){
                dis[i][j]=inf;
                if(!(i^j))dis[i][j]=0;
            }
        for (register int i=1; i<=e; ++i){register int x=in(),y=in(),c=in();dis[x][y]=dis[y][x]=min(dis[x][y],c);}
    }
    void floyd(){
        for (int k=1; k<=v; ++k)
            for (register int i=1; i<=v; ++i)
                for (int j=1; j<=v; ++j)
                    if (i^j&&i^k&&j^k)
                        if(dis[i][j]>dis[i][k]+dis[k][j])
                            dis[i][j]=dis[i][k]+dis[k][j];
    }
    void dp(){
        if (n==1) {puts("0.00");return;}
        for (register int i=0; i<=m; ++i) f[1][i][0]=f[1][i][1]=0;
        for (register int i=2; i<=n; ++i)
            for (register int j=0; j<=min(i,m); ++j){
                f[i][j][0]=f[i][j][1]=inf;
                if(i^j){
                    if((i-1)^j) f[i][j][0]=min(f[i][j][0],f[i-1][j][0]+dis[c[i-1]][c[i]]);
                    if(j) f[i][j][0]=min(f[i][j][0],f[i-1][j][1]+qw[i-1]*dis[d[i-1]][c[i]]+(1-qw[i-1])*dis[c[i-1]][c[i]]);
                    if (!(i^n)) ans=min(ans,f[i][j][0]);
                }
                if(j){
                    if(j>1) f[i][j][1]=f[i-1][j-1][1]+qw[i-1]*qw[i]*dis[d[i-1]][d[i]]+qw[i-1]*(1-qw[i])*dis[d[i-1]][c[i]]+(1-qw[i-1])*qw[i]*dis[c[i-1]][d[i]]+(1-qw[i-1])*(1-qw[i])*dis[c[i-1]][c[i]];
                    if(i^j) f[i][j][1]=min(f[i][j][1],f[i-1][j-1][0]+qw[i]*dis[c[i-1]][d[i]]+(1-qw[i])*dis[c[i-1]][c[i]]);
                    if (!(i^n)) ans=min(ans,f[i][j][1]);
                }
            }
        printf("%.2lf",ans);
    }
    int main(){init();floyd();dp();return 0;}

    D2T1(problem)

    题意:自己看题目。

    解题思路:杨辉三角形递推预处理即可,注意对k取余。

    #include<stdio.h>
    #define max(a,b) (a>b?a:b)
    int t,k,n[10001],m[10001],mn,f[2005000],ans[2005000];
    inline int in(){
        int x=0,f=1; char c=getchar();
        while(c<'0'||c>'9') f=c=='-'?-1:1,c=getchar();
        while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
        return x*f;
    }
    inline int doit(int n,int m){return n*(n+1)/2+m;}
    void init(){
        t=in(),k=in();  
        for (register int i=1; i<=t; ++i){n[i]=in();m[i]=in();mn=max(n[i],mn);}
        for (register int i=0; i<=mn; ++i) f[doit(i,0)]=1;
        for (register int i=1; i<=mn; ++i)
            for (register int j=1; j<=i; ++j)
                if(i^j){
                    ans[doit(i,j)]=ans[doit(i-1,j)]+ans[doit(i,j-1)]-ans[doit(i-1,j-1)];
                    f[doit(i,j)]=(f[doit(i-1,j-1)]+f[doit(i-1,j)])%k;
                    if (!(f[doit(i,j)]%k)) ans[doit(i,j)]++;
                }
                else{
                    ans[doit(i,j)]=ans[doit(i,j-1)];
                    f[doit(i,j)]=f[doit(i-1,j-1)];
                    if (!(f[doit(i,j)]%k)) ans[doit(i,j)]++;
                }
    }
    void solve(){
        for (register int i=1; i<=t; ++i)
            if (n[i]<m[i]) printf("%d
    ",ans[doit(n[i],n[i])]);
            else printf("%d
    ",ans[doit(n[i],m[i])]);
    }
    int main(){init();solve();return 0;}

    D2T2(earthworm)

    题意:就是你每次会选一堆东西中最长的出来,然后切成2部分再扔回去,叫你模拟出这个过程。

    解题思路:正常的想法是扔个堆,然后按题意搞,时间会T((O((n+m)lg (n+m) )))。容易发现切出来的东西其实是有单调性的= =,然后就可以用3个队列(1个初始队列,2个切出来的队列)愉快的优化了,时间效率是(O(n lg n+m ) )

    /*代码在luogu上T了1个点。。。估计评测机太慢= =,BZOJ上过了,就假装没问题吧。*/

    #include <stdio.h>
    #include <algorithm>
    #include <math.h>
    #include <iostream>
    #define MN 100005
    #define MM 7000005
    #define ll long long
    #define inf 0x7fffffffffffffffLL
    #define max(a,b) (a>b?a:b) 
    using namespace std;
    int h[3],t[3],m,tt,dl;
    ll que[3][MN+MM],q,u,v;
    inline int in(){
        int x=0,f=1; char ch=getchar();
        while (ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    inline ll get_top(){
        ll ma=-inf;dl=-1;
        for (register int i=0; i<3; ++i)
            if (h[i]<=t[i]&&que[i][h[i]]>ma) ma=que[i][h[i]],dl=i;
        if (dl!=-1) ++h[dl];return ma;
    }
    void init(){
        t[0]=in(),m=in(),q=in(),u=in(),v=in(),tt=in();
        for (int i=1; i<=t[0]; ++i) que[0][i]=in();
        sort(que[0]+1,que[0]+1+t[0],greater<int>());
        h[0]=h[1]=h[2]=1;
    }
    void solve(){
        for (register int i=1; i<=m; ++i){
            ll w=get_top()+(i-1)*q;
            if (i%tt==0) if (i/tt==1) printf("%lld",w);
                        else printf("% lld",w);
            que[1][++t[1]]=w*u/v-i*q;
            que[2][++t[2]]=w-(w*u/v)-i*q;
        }putchar('
    ');
        for (register int i=1; ; ++i){
            ll w=get_top()+m*q;
            if (dl==-1) break;
            if (i%tt==0) if (i/tt==1) printf("%lld",w);else printf("% lld",w);
        }
    }
    int main(){init();solve();return 0;}

     D2T3(angrybirds)

    题意:给你n个点,你需要用最少的过原点的抛物线将这些点覆盖,求最少的抛物线数。

    解题思路:首先,3点定抛物线,因为过原点,所以是2点定抛物线,然后暴力算任意2点连的抛物线,接着在此基础上O(n)算出这条抛物线直接经过了多少个点,最后根据这个跑一次状压DP即可。

    #include <stdio.h>
    #include <string.h>
    #define eps 1e-8
    #define abs(x) (x<0?(-1)*(x):x)
    #define MN 18
    double x[MN],y[MN];
    int f[MN][MN],dp[1<<MN],n,m;
    inline void init(){
        scanf("%d%*d",&n);
        for (register int i=0; i<n; ++i) scanf("%lf%lf",&x[i],&y[i]),y[i]/=x[i];
        memset(f,0,sizeof(f));
        for (register int i=0; i<n; ++i)
            for (register int j=0; j<n; ++j)
                if (i^j){
                    register double a=(y[i]-y[j])/(x[i]-x[j]); if (a>=0) continue;
                    register double b=(x[i]*y[j]-x[j]*y[i])/(x[i]-x[j]);
                    for (register int k=n-1; k+1; --k)
                        f[i][j]=(f[i][j]<<1)+(abs(a*x[k]+b-y[k])<eps);
                }
    }
    inline void solve(){
        memset(dp,0x3f,sizeof(dp));dp[0]=0;
        for (register int i=0; i<(1<<n)-1; ++i){
            register int j=0;for (; i&(1<<j); ++j);
            if (dp[i]+1<dp[i|(1<<j)]) dp[i|(1<<j)]=dp[i]+1;
            for (register int k=0; k<n; ++k)
                if (dp[i]+1<dp[i|f[j][k]])    dp[i|f[j][k]]=dp[i]+1;
        }
        printf("%d
    ",dp[(1<<n)-1]);
    }
    int main(){int T;scanf("%d",&T);while(T--) init(),solve();return 0;}
  • 相关阅读:
    使用 SailingEase WinForm 框架构建复合式应用程序(插件式应用程序)
    SailingEase WinForm 应用程序开发框架
    SailingEase WinForm 框架 DEMO 下载
    SailingEase WinForm 开发框架
    .net动态编译
    VS2010 如何修改程序菜单字体大小?
    Android C++回收机制(转)
    遥测的死区
    发现个开源很好的C++框架库,共享一下
    mongodb查询例子
  • 原文地址:https://www.cnblogs.com/Melacau/p/NOIPTG2016solution.html
Copyright © 2020-2023  润新知