zoukankan      html  css  js  c++  java
  • Gym 101655:2013Pacific Northwest Regional Contest(寒假自训第13场)

    A .Assignments

    题意:给定距离D,以及N个飞机的速度Vi,单位时间耗油量Fi,总油量Ci。问有多少飞机可以到达目的地。

    思路:即问多少飞机满足(Ci/Fi)*Vi>=D  ---->  Ci*Vi>=Fi*D; 

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    int main()
    {
        int T,N,f,v,c,D,ans;
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&N,&D); ans=0;
            rep(i,1,N){
                 scanf("%d%d%d",&v,&f,&c);
                if(f*v>=D*c) ans++;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }

    B .Bones’s Battery

    题意:N城市,M条双向带权路(权值表示耗电量),满足他们连通。 每个城市可以给电车充满电。 现在需要一种电车,满足任意路线(即任意点到任意点),它充电的次数不超过K。 一开始车的没电的,即起点必须充电。

    思路:先Floyd求得两两最短路。 然后我们把dis小于电车电量的路径距离看为1,然后需要满足任意点对距离不大于K。显然就是一个二分+Floyd。

    二分的时候可以直接二分[1,inf]; 复杂度O(N^3*loginf).

    优化:二分的这个电量,一定是其中两点间距离,我们我们把点对距离排序,然后对他们二分即可。 复杂度O(2*N^3*logN);

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=101;
    const ll inf=100000000000000;
    int N,M,K;ll dis[maxn][maxn],dp[maxn][maxn];
    bool check(ll Mid)
    {
        rep(i,1,N)
          rep(j,1,N) dp[i][j]=(dis[i][j]>Mid?inf:1);
        rep(k,1,N) 
          rep(i,1,N) 
           rep(j,1,N)
            dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
        rep(i,1,N)
          rep(j,i+1,N)
              if(dp[i][j]>K) return false;
        return true;
    }
    int main()
    {
    
        int T,u,v;ll w;
        scanf("%d",&T);
        while(T--){
           scanf("%d%d%d",&N,&K,&M);
           rep(i,1,N) rep(j,1,N) dis[i][j]=inf;
           rep(i,1,M){
             scanf("%d%d%lld",&u,&v,&w); u++; v++;
             dis[u][v]=min(dis[u][v],w);
             dis[v][u]=min(dis[v][u],w);
           }
           rep(k,1,N) 
            rep(i,1,N) 
             rep(j,1,N) 
              dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
           ll L=1,R=inf,Mid,ans;
           while(L<=R){
             Mid=(L+R)/2;
             if(check(Mid)) ans=Mid,R=Mid-1;
             else L=Mid+1;
           }
           printf("%lld
    ",ans);
        }
        return 0;
    }

    C .Crusher’s Code

    题意:给定长度为N的序列a[];

                   Alice每次随机选择一个i,j;如果a[min(i,j)]>a[max(i,j)],则交换他们两个。

                   Bob每次随机选择一个i(i<N);如果a[i]>a[i+1],则交换他们两个。

    思路:然后是一个有限状态的数学期望DP,我们可以记忆化搜索。 把a数组看成一个N位数,假设为x,那么每次它要么不变,要么变小。

    对于Alice和Bob,我们可以列出方程 :dp[x]=(dp[a]+dp[b]+dp[c]+dp[d]....dp[cnt])/cnt+1;其中abcd...是x能到达的状态。

    显然总状态数小于N!~4e4;我们可以过,假设map保存dp值,复杂度O(N!*log);

    优化:我们可以把map换为康拓展开,这样可以优化掉一个log。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    int a[10],b[10],f[10],N,Tar;
    map<int,double>mp;
    double dfs1(int x)
    {
        if(x==Tar) return 0;
        int c[10];
        if(mp.find(x)!=mp.end()) return mp[x];
        double res=0; int cnt=0,tx=x;
        for(int i=N;i>=1;i--) c[i]=tx%10,tx/=10;
        rep(i,1,N)
         rep(j,1,N){
            int mn=min(i,j),mx=max(i,j);
            if(c[mn]>c[mx]) res+=dfs1(x-(c[mn]*f[N-mn]+c[mx]*f[N-mx])+(c[mx]*f[N-mn]+c[mn]*f[N-mx]));
            else cnt++;
        }
        return mp[x]=(res+N*N)/(N*N-cnt);
    }
    double dfs2(int x)
    {
        if(x==Tar) return 0;
        int c[10];
        if(mp.find(x)!=mp.end()) return mp[x];
        double res=0; int cnt=0; int tx=x;
        for(int i=N;i>=1;i--) c[i]=tx%10,tx/=10;
        rep(i,1,N-1) {
            int mn=i,mx=i+1;
            if(c[mn]>c[mx]) res+=dfs2(x-(c[mn]*f[N-mn]+c[mx]*f[N-mx])+(c[mx]*f[N-mn]+c[mn]*f[N-mx]));
            else cnt++;
        }
        mp[x]=(res+N-1)/(N-1-cnt);
        return mp[x];
    }
    int main()
    {
        int T; scanf("%d",&T);
        f[0]=1; rep(i,1,9) f[i]=f[i-1]*10;
        while(T--){
            scanf("%d",&N);
            rep(i,1,N) scanf("%d",&a[i]),b[i]=a[i];
            sort(b+1,b+N+1);
            int tot=unique(b+1,b+N+1)-(b+1);
            rep(i,1,N) a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
            int x=0; rep(i,1,N) x=x*10+a[i],b[i]=a[i];
            sort(b+1,b+N+1);
            Tar=0; rep(i,1,N) Tar=Tar*10+b[i];
            mp.clear(); double ans1=dfs1(x);
            mp.clear(); double ans2=dfs2(x);
            printf("Monty %.6lf Carlos %.6lf
    ",ans1,ans2);
        }
        return 0;
    }

    D .Delta Quadrant

    题意:给定大小为N的一棵带权树,让你找一条最快的路径,遍历至少N-K个点,然后回到起点,K<=20。

    思路:树型DP,dp[i][j]表示选择以i为根的子树,子树里有j个点不选的最小权值和。

    和一般的树DP做背包不一样,这里必须选一个,所以我们用一个临时数组tmp来更新。

    更新答案的时候,选择的连通块的根也不一定是1号节点。

    复杂度O(N*K^2);

    #include<bits/stdc++.h>
    #define ll long long
    #define rep2(i,a,b) for(int i=a;i>=b;i--)
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=200010;
    const int inf=1e9;
    int  Laxt[maxn],Next[maxn],To[maxn],Len[maxn];
    int dp[maxn][22],tmp[22],sz[maxn],cnt,K;
    void add(int u,int v,int w)
    {
        Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=w;
    }
    void dfs(int u,int f)
    {
        rep(i,1,K) dp[u][i]=0;
        dp[u][0]=0; sz[u]=1;
        for(int i=Laxt[u];i;i=Next[i]){
            int v=To[i]; if(v==f) continue;
            dfs(v,u); sz[u]+=sz[v];
            rep(j,0,K) tmp[j]=inf;
            rep(j,0,min(sz[v],K)){
                rep2(k,K,j)
                tmp[k]=min(tmp[k],dp[u][k-j]+dp[v][j]+(j==sz[v]?0:Len[i]));
            }
            rep(j,0,K) dp[u][j]=tmp[j];
        }
    }
    int main()
    {
        int T,N,u,v,w; scanf("%d",&T);
        while(T--){
            scanf("%d%d",&N,&K);
            cnt=0; rep(i,1,N) Laxt[i]=0;
            rep(i,1,N-1) {
                scanf("%d%d%d",&u,&v,&w);
                u++; v++;
                add(u,v,w); add(v,u,w);
            }
            dfs(1,0); int ans=dp[1][0];
            rep(i,1,K)  ans=min(ans,dp[1][K]);
            rep(i,1,N) rep(j,0,K-(N-sz[i])) ans=min(ans,dp[i][j]);
            printf("%d
    ",ans*2);
        }
        return 0;
    }

    E .Enterprising Escape

    题意:给定N*M的迷宫,迷宫由大写字母组成,每种不同的字母对应穿过这个格子的时间,‘E’是起点,问从起点走到迷宫边界的最小时间。

    思路:没有负权,所以直接BFS或者跑最短路即可。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=1010;
    const int inf=1e9;
    int dis[maxn][maxn],inq[maxn][maxn],id[maxn],C,N,M,Sx,Sy,ans;
    int dx[4]={1,0,0,-1},dy[4]={0,1,-1,0};char c[maxn][maxn];
    struct in{
        int x,y,d;
        in(){}
        in(int xx,int yy,int dd):x(xx),y(yy),d(dd){}
        bool friend operator<(in w,in v){ return w.d>v.d; }
    };
    void dijs()
    {
    
        rep(i,1,N) rep(j,1,M) dis[i][j]=inf,inq[i][j]=0;
        dis[Sx][Sy]=0;  priority_queue<in>q;
        q.push(in(Sx,Sy,0));
        while(~q.empty()){
            int x=q.top().x,y=q.top().y; q.pop(); inq[x][y]=0;
            if(x==1||x==N||y==1||y==M){
                ans=dis[x][y]; return;
            }
            rep(i,0,3){
                int tx=x+dx[i],ty=y+dy[i];
                if(tx>=1&&tx<=N&&ty>=1&&ty<=M&&dis[tx][ty]>dis[x][y]+id[c[tx][ty]]){
                    dis[tx][ty]=dis[x][y]+id[c[tx][ty]];
                    if(!inq[tx][ty]) inq[tx][ty]=1,q.push(in(tx,ty,dis[tx][ty]));
                }
            }
        }
    }
    int main()
    {
        int T,x; char s[3];
        scanf("%d",&T);
        while(T--){
            scanf("%d%d%d",&C,&M,&N);
            rep(i,1,C){
                scanf("%s",s); scanf("%d",&x);
                id[s[0]]=x;
            }
            rep(i,1,N) scanf("%s",c[i]+1);
            rep(i,1,N) rep(j,1,M) {
                if(c[i][j]=='E') {
                    Sx=i; Sy=j; break;
                }
            }
            dijs();
            printf("%d
    ",ans);
        }
        return 0;
    }

    F .Federation Favorites

    题意:问一个数是否是真因子(不含本身的因子)之和。

    思路:根号分解即可。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define rep2(i,a,b) for(int i=a;i>=b;i--)
    using namespace std;
    const int maxn=1010;
    int tot,a[maxn],b[maxn],tot2;
    int main()
    {
        int N;
        while(~scanf("%d",&N)&&N!=-1){
            int res=1; a[tot=1]=1; tot2=0;
            for(int i=2;i*i<=N;i++){
                if(N%i==0) {
                    res+=i; a[++tot]=i;
                    if(i*i!=N) res+=N/i,b[++tot2]=N/i;
                }
            }
            if(res!=N) printf("%d is NOT perfect.
    ",N);
            else {
                printf("%d = %d",N,1);
                rep(i,2,tot) printf(" + %d",a[i]);
                rep2(i,tot2,1) printf(" + %d",b[i]);
                puts("");
            }
        }
        return 0;
    }

    G .Generations of Tribbles

    题意:给一个递推式,求第N项。

    思路:模拟。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define rep2(i,a,b) for(int i=a;i>=b;i--)
    using namespace std;
    const int maxn=1010;
    ll a[maxn]; int N,T;
    int main()
    {
        a[0]=a[1]=1; a[2]=2; a[3]=4;
        rep(i,4,67) a[i]=a[i-1]+a[i-2]+a[i-3]+a[i-4];
        scanf("%d",&T);
        while(T--){
            scanf("%d",&N);
            printf("%llf
    ",a[N]);
        }
        return 0;
    }

    H .Holodeck Hacking

    题意:rev(X)是把X的各个数位倒序过来,给定Y,问多少X满足X+rev(X)=Y;Y<1e18;

    思路:假设X=abcd,那么X+rev(X)=(a+d)(b+c)(b+c)(a+d),然后进位。    即在不进位的情况下是对称的。那么我们枚举不进位的情况下的右半部分,然后对称到左半部分,然后考虑进位,进位后如果值为Y,然后分别考虑每一位的贡献。

    这样的话复杂度是O(2^((L+1)/2);  然后累乘每一位的贡献即可。 估计数位DP也可以做,但是复杂度一样。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=5001;
    int a[maxn],b[maxn],c[maxn],tot;ll x,ans;
    void dfs(int L,int pos,int p)
    {
        if(pos==(L+1)/2+1){
            for(int i=pos;i<=L;i++) b[i]=b[L+1-i];
            for(int i=1;i<=tot+1;i++) c[i]=0;
            for(int i=1;i<=L;i++){
                    c[i]+=b[i];
                    c[i+1]=c[i]/10;
                    c[i]%=10;
            }
            if(c[tot+1]) return ;
            for(int i=1;i<=tot;i++) if(c[i]!=a[i]) return ;
            ll res;
            if(b[1]<10){
                if(L==1) res=b[1]&1?0:1;
                else res=b[1];
            }
            else {
                if(L==1) res=b[1]&1?0:1;
                else res=19-b[1];
            }
            for(int i=2;i<pos;i++){
                if(b[i]<10){
                    if(L+1-i==i) res*=b[i]&1?0:1;
                    else res*=1LL*(b[i]+1);
                }
                else{
                    if(L+1-i==i) res*=b[i]&1?0:1;
                    else res*=1LL*(19-b[i]);
                }
            }
            ans+=res;
            return ;
        }
        if(a[pos]-p>=0) b[pos]=a[pos]-p,dfs(L,pos+1,0);
        b[pos]=a[pos]-p+10; dfs(L,pos+1,1);
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--){
            scanf("%lld",&x); tot=0; ans=0;
            while(x) a[++tot]=x%10,x/=10;
            dfs(tot,1,0);
            if(a[tot]==1) dfs(tot-1,1,0);
            printf("%lld
    ",ans);
        }
        return 0;
    }

    I .Interstellar Trade

    题意:X轴有处于整点的N个点, 现在你可以任选两个点(不一定在整点上),使得这两个点可以互相瞬移,求最小化最大距离。

    思路:比赛的时候写了个O(N^3)的代码,显然过不去,然后乱改成N^2的假代码,瞎交了一发,估计是数据水了A了。

    (下面的别人的代码,还未理解。

    #include<bits/stdc++.h>
    #define ll long long
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=5001;
    int N,a[maxn];
    int main()
    {
        int T,ans;
        scanf("%d",&T);
        while(T--){
            scanf("%d",&N);
            rep(i,1,N) scanf("%d",&a[i]);
            sort(a+1,a+N+1); ans=0;
            rep(i,1,N) ans=max(ans,min(a[N]-a[i],a[i]-a[1]));
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    NHibernate源码分析
    jQuery插件:跨浏览器复制jQuery-zclip
    NHibernate入门实例
    NHibernate系列之一--刘东
    关于登陆窗口的关闭、传值
    java 内部类 多线程
    插入时排序
    按某些字段排序数据
    获取顺序排列
    Oracle数组类型
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10388024.html
Copyright © 2011-2022 走看看