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\n",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\n",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\n",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\n",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\n",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",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\n",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\n",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\n",ans);
    }
    return 0;
}

 

posted @ 2019-02-16 15:56  nimphy  阅读(255)  评论(4编辑  收藏