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]);
}
posted @ 2021-05-28 16:39  letitdown  阅读(58)  评论(0编辑  收藏  举报