清北考前刷题da7下午好

三向城

 

/*
原图一定是一棵完全二叉树。
根节点是x,左节点是x*2,右节点是x*2+1
转化为二进制往左右走就很明显了。
*/ 
#include<iostream>
#include<cstdio>
#include<cstring>

#define ll long long

using namespace std;
int T,x,y,k,ans,pos;

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

int main()
{
    freopen("city.in","r",stdin);
    freopen("city.out","w",stdout);
    T=read();
    while(T--)
    {
        x=read();y=read();ans=0;
        if(x==y){printf("1\n");continue;}
        while(x!=y)
        {
            if(x>y) x/=2,ans++;
            if(y>x) y/=2,ans++;
        }
        printf("%d\n",ans);
     }
     return 0;
}

 

 

灵魂画师

 

 

/*
dp[i][j][k]表示第i个元素经过j次染色变为k颜色的概率。
考虑一段区间,每个元素只有选和不选两个状态,所以概率都为1/2.
转移的时候枚举下一个染不染和染成什么颜色。染成下一种颜色的概率是1/c。
可以看出第一维是没有用的,因为被覆盖次数相同的格子概率是相同的。
*/
#include<iostream>
#include<cstdio>
#include<cstring>

#define N 107

using namespace std;
int n,m,tot,c,k,t,l,r,cnt[N];
double dp[N][N],ans;

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

void DP()
{
    dp[0][1]=1;
    for(int i=0;i<tot;i++)
    {
        for(int j=0;j<c;j++) 
        {
            dp[i+1][j]+=dp[i][j]/2;
            for(int x=0;x<c;x++) dp[i+1][(j*x)%c]+=dp[i][j]/(2*c);
        }
    }
    
    for(int i=1;i<=n;i++)
      for(int j=0;j<c;j++)
        ans+=dp[cnt[i]][j]*j;
    printf("%.3lf\n",ans);
}

int main()
{
    freopen("paint.in","r",stdin);
    freopen("paint.out","w",stdout);
    n=read();c=read();k=read();
    for(int i=1;i<=k;i++)
    {
        l=read();r=read();
        for(int j=l;j<=r;j++)
            cnt[j]++,tot=max(tot,cnt[j]);
    }DP();
    return 0;
}

 

 

香子兰

#include <cstdio>
#define inf 1000000007
#define N 24
int a[N][N],d[N][N],f[2][N][1050000],e[N],cnt[1050000];
int n,n1,n2,x,y,z,i,j,m,k,q,ans,sta;

int main()
{
    freopen("vanilla.in", "r", stdin);
    freopen("vanilla.out", "w", stdout);
    e[0] = 1;
    //预处理2^i
    for (i=1; i<=22; ++i) 
    e[i] = e[i-1]<<1;
    //预处理每个二进制数中有几个1
    for (i=0; i<e[20]; ++i)
    for (x=i; x!=0; x>>=1) 
    cnt[i] += x&1;

    scanf("%d%d", &n, &m);
    for (i=1; i<=n; ++i)
    for (j=1; j<=n; ++j) 
    d[i][j] = inf*(i!=j);
    for (i=1; i<=m; ++i)
    {
        scanf("%d%d%d", &x, &y, &z);
        ++x;++y;
        if (z<d[x][y]) 
        d[x][y] = d[y][x] = z;
    }
    
    // floyd求两两最短路
    for (k=1; k<=n; ++k)
    for (i=1; i<=n; ++i)
    for (j=1; j<=n; ++j)
    if (d[i][k]+d[k][j] < d[i][j])
    d[i][j] = d[i][k]+d[k][j];

    if (n == 3)
    {
        printf("%d\n", (d[1][2]+d[2][3])*2);
        return 0;
    }
    
    n1 = (n-2)/2;
    n2 = n-2-n1;
    //求从家、花店开始,走到点i,经过的点为j的最短路
    //q=0:从家开始,q=1:从花店开始
    for (q=0; q<=1; ++q)
    {
        //初始化状态
        for (i=1; i<=n; ++i)
        for (j=0; j<e[n-2]; ++j) 
        f[q][i][j] = inf;
        if (q == 0)
        {
            for (i=2; i<n; ++i) 
            f[q][i][e[i-2]] = d[1][i];
        }
        else
        {
            for (i=2; i<n; ++i) 
            f[q][i][e[i-2]] = d[n][i];
        }
        
        //dp
        for (j=1; j<e[n-2]; ++j)
          if (cnt[j] < n2)
          for (i=2; i<n; ++i)
            if (f[q][i][j] < inf)
            for (k=2; k<n; ++k)
              if (f[q][i][j]+d[i][k] < f[q][k][j|e[k-2]]) 
                f[q][k][j|e[k-2]] = f[q][i][j]+d[i][k];
    }
    
    ans = inf;
    //枚举先走到的一半为sta
    for (sta=0; sta<e[n-2]; ++sta)
    if (cnt[sta] == n1)
    {
        //前半段
        x = inf; //x记录前半段的最短距离
        //枚举前一半中最后一个收割的点是i
        for (i=2; i<n; ++i)
        if (sta&e[i-2])
        //枚举后一半中第一个收割的点是j
        for (j=2; j<n; ++j)
        if (!(sta&e[j-2]))
        if (f[0][i][sta]+d[i][j]+f[1][j][e[n-2]-1-sta] < x) 
        x = f[0][i][sta]+d[i][j]+f[1][j][e[n-2]-1-sta];
        
        
        //后半段
        //枚举前一半中最后一个播种的点是i
        for (i=2; i<n; ++i)
        if (sta&e[i-2])
        //枚举后一半中第一个播种的点是j
        for (j=2; j<n; ++j)
        if (!(sta&e[j-2]))
        if (x+f[1][i][sta]+d[i][j]+f[0][j][e[n-2]-1-sta] < ans) 
        ans = x+f[1][i][sta]+d[i][j]+f[0][j][e[n-2]-1-sta];
    }
    printf("%d\n", ans);
    return 0;
}

 

posted @ 2017-11-03 21:52  安月冷  阅读(193)  评论(0编辑  收藏  举报