20210524
T1
由于蒟弱太弱,所以只会打暴力dp了。
设\(f[i][j]\)表示\(i\)时间正好玩完\(j\)点的期望高兴值,
可以想到每个点一开始都会是\(f[c[i]][i]\)为\(w[i]/n\),\(pre[c[i]][i]=1\)。(\(pre[i][j]\)是记录\(i\)时间有多少种方式到\(j\)点的数组,每个点一开始初始化为1)
然后进行状态转移,用\(cou\)表示现在来得及玩的下一个点的个数(设为\(k\)),
则\(f[i+w[j->k]+c[k]]+=(f[i][j]+h[k]*pre[i][j])/cou;\)(因为有\(pre[i][j]/cou\)的路径到k,所以加这么多h[k])
\(pre[i+w[j->k]+c[k]]+=pre[i][j]/cou\)
如果\(cou=0\)则说明要终止了,\(ans+=f[i][j]\)(终止时期望的开心值),
\(tot\)记录总路径数。\(tot+=pre[i][j]\)(pre同上)
最后\(ans=ans/tot\)。
然后本题就出来了~
被与掰D了...tot与n最后等价,也可以不记录。
Code
#include<bits/stdc++.h>
using namespace std;
int read()
{
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 n,m,K,co,head[131],h[131][3],c[131];
#define db double
db f[500][135][3],ans1,ans2,pre[500][135],tot;
struct node{int next,to,w;}e[20110];
void add(int next,int to,int w){e[++co].next=head[next],e[co].w=w,e[co].to=to,head[next]=co;}
int main()
{
n=read();m=read();K=read();
for(int i=1;i<=n;i++)c[i]=read(),h[i][1]=read(),h[i][2]=read();
for(int i=1,x,y,z;i<=m;i++){x=read(),y=read(),z=read();add(x,y,z);add(y,x,z);}
for(int i=1;i<=n;i++)f[c[i]][i][1]=(db)h[i][1],f[c[i]][i][2]=(db)h[i][2],pre[c[i]][i]=1;
for(int i=1;i<=K;i++)
{
for(int j=1;j<=n;j++)
{
if(f[i][j][1]||f[i][j][2])
{
int cou=0;
for(int k=head[j];k;k=e[k].next)
{
int w=e[k].w,l=e[k].to;
if(w+c[l]+i>K)continue;
cou++;
}
if(cou==0)
{
ans1+=f[i][j][1];
tot+=pre[i][j];
ans2+=f[i][j][2];
}
else
{
for(int k=head[j];k;k=e[k].next)
{
int w=e[k].w,l=e[k].to;
if(w+c[l]+i>K)continue;
pre[w+c[l]+i][l]+=pre[i][j]/(db)cou;
f[w+c[l]+i][l][1]+=f[i][j][1]/(db)cou+(db)h[l][1]*pre[i][j]/(db)cou;
f[w+c[l]+i][l][2]+=f[i][j][2]/(db)cou+(db)h[l][2]*pre[i][j]/(db)cou;
}
}
}
}
}
printf("%.5lf %.5lf",ans1/tot,ans2/tot);
}
T2
由于蒟弱太弱,所以还是只会打暴力树形dp了。
设\(f[i][j]\)表示\(i\)点状态为\(j\)的最小步数。
j的状态表示为1-按,亮 2-不按,亮 3-不按,不亮
然后\(dfs\)就可以愉快地dp了~
code
#include<cmath>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
//j的状态表示为1-按,亮 2-不按,亮 3-不按,不亮
int read(){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 n,f[150][4],head[150],co;
const int maxn=0x3f;
struct node{int next,to;}e[310];
void add(int next,int to){e[++co].next=head[next],e[co].to=to,head[next]=co;}
int min(int a,int b){return a<b?a:b;}
void dfs(int k,int fa)
{
f[k][1]=1;f[k][2]=f[k][3]=0;
int sum=0,mn=maxn,cnt=0,cnt2=0;
for(int i=head[k],j;i;i=e[i].next)
{
if(e[i].to==fa)continue;
j=e[i].to;cnt2++;dfs(j,k);
f[k][1]+=f[j][3];
if(f[j][1]<f[j][2]){sum+=f[j][1];cnt++;}
else{sum+=f[j][2];}
mn=min(mn,abs(f[j][1]-f[j][2]));
}
if(cnt2==0)
{
f[k][1]=1;
f[k][2]=maxn;
f[k][3]=0;
}
else
{
if(cnt%2)
{
f[k][2]+=sum;
f[k][3]+=sum+mn;
}
else
{
f[k][3]+=sum;
f[k][2]+=sum+mn;
}
}
}
int main()
{
while(1)
{
n=read();if(!n)return 0;
co=0;memset(head,0,sizeof(head));memset(e,0,sizeof(e));
for(int i=1;i<n;i++){int x=read(),y=read();add(x,y);add(y,x);}
dfs(1,0);
printf("%d\n",min(f[1][1],f[1][2]));
}
}
T3
数据范围小,可以状压。设\(f[i][j][k][l]\)表示到\((n-i)\)点\(j\)边状态为\(k\),
连了\((i-k)\)~\((i-l+1)\)的点的方案数。
其中\(k\)表示每个点的边数是否为奇数,是为1,不是为0.
那么有三种情况:
1.这已经是\(i\)点到(i-l+1)的最后一条边了:
f[i][j][k][l-1]=add(f[i][j][k][l-1],f[i][j][k][l]);
2.向现在要连的点多连一条边:
f[i][j+1][k^1^(1<<l)][l]=add(f[i][j+1][k^1^(1<<l)][l],f[i][j][k][l]);
3.现在不连\(i\)点了,如果每个点都符合边数为0,则连\(i-1\)个点:
f[i+1][j][k<<1][min(K,i)]=add(f[i+1][j][k<<1][min(K,i)],f[i][j][k][0]);
然后就可以愉快转移了~
Code
#include<cmath>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
int read(){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;}
#define ll long long
const ll mod=1000000007;
int n,m,K;
ll add(ll a,ll b){return a+b>mod?a+b-mod:a+b;}
ll min(ll a,ll b){return a<b?a:b;}
ll f[32][32][1025][10];//f[i][j][k][l]到i点j边状态为k 连了(i-k)~(i-t+1)
int main()
{
n=read();m=read();K=read();
f[1][0][0][0]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
for(int k=0;k<=(1<<(K+1))-1;k++){
for(int l=min(i,K);l;l--)
{
f[i][j][k][l-1]=add(f[i][j][k][l-1],f[i][j][k][l]);
f[i][j+1][k^1^(1<<l)][l]=add(f[i][j+1][k^1^(1<<l)][l],f[i][j][k][l]);
}
if((k&(1<<K))==0)
{
f[i+1][j][k<<1][min(K,i)]=add(f[i+1][j][k<<1][min(K,i)],f[i][j][k][0]);
}
}
printf("%lld\n",f[n][m][0][0]);
}