三向城


/*
原图一定是一棵完全二叉树。
根节点是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
");continue;}
while(x!=y)
{
if(x>y) x/=2,ans++;
if(y>x) y/=2,ans++;
}
printf("%d
",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
",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
", (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
", ans);
return 0;
}