题解:
设状态\(F[S]\),分四个阶段转移:
1.\(F[S]\)表示可以组成集合\(S\)的有多少盒子
2.\(F[S]\)表示可以组成\(S\)的子集的有多少盒子
3.\(F[S]\)表示并集为\(S\)的方案数
4.\(F[S]\)表示有多少种方式可以表示\(S\)的子集
答案即第三阶段时的\(F[\)全集\(]\)
\(code\):
#include<stdio.h>
#include<ctype.h>
using namespace std;
char buf[1<<20],*p1,*p2;
inline char gc()
{
// return getchar();
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}
template<typename T>
inline void read(T &x)
{
char tt;
while(!isdigit(tt=gc()));x=tt-'0';
while(isdigit(tt=gc())) x=x*10+tt-'0';
}
int n,m,tot;
int f[1<<23],pow_[1<<23];
const int mod=1e9+7;
inline int add(int a,int b){return a+b<mod?a+b:a+b-mod;}
inline int sub(int a,int b){return a-b<0?a-b+mod:a-b;}
int main()
{
read(n),read(m);
tot=1<<m;
for(int i=1;i<=n;i++)
{
int t,x,s=0;read(t);
for(int j=1;j<=t;j++)
read(x),s|=1<<(x-1);f[s]++;
}
for(int i=0;i<m;i++)
for(int s=0;s<tot;s++)
if(s>>i&1)
f[s]=add(f[s],f[s^(1<<i)]);
pow_[0]=1;
for(int i=1;i<=(1<<22);i++)
pow_[i]=add(pow_[i-1],pow_[i-1]);
for(int s=0;s<tot;s++)
f[s]=pow_[f[s]];
for(int i=0;i<m;i++)
for(int s=0;s<tot;s++)
if(s>>i&1)
f[s]=sub(f[s],f[s^(1<<i)]);
printf("%d",f[tot-1]);
}
题解:(copy出题人原话)
一个状态应该包含,每种颜色的剩余数量,以及当前画的最后一笔的颜色。
所以状态就是\(f[k][(i_1...,i_n)]\)表示最后一笔颜色为k,各颜色还剩.... in支的时候,颜色段数的期望值。
这样并不能递推,还缺一个辅助的状态\(p[k][(i_1,...i_n)]\), 表示到达当前状态的概率。
\(code:\)(已更新为\(mycode\))
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<ctype.h>
#include<queue>
#include<string.h>
#include<vector>
using namespace std;
char buf[1<<20],*p1,*p2;
inline char gc()
{
return getchar();
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}
template<typename T>
inline void read(T &x)
{
char tt;
while(!isdigit(tt=gc()));x=tt-'0';
while(isdigit(tt=gc())) x=x*10+tt-'0';
}
int n,t[10],tmp;
int a[6];
double p[6][16][16][16][16][16];
double f[6][16][16][16][16][16];
int main()
{
read(n);
for(int i=1;i<=n;i++) read(t[i]),tmp+=t[i];
if(t[1]>0)
f[1][t[1]-1][t[2]][t[3]][t[4]][t[5]]=
p[1][t[1]-1][t[2]][t[3]][t[4]][t[5]]=1.0*t[1]/tmp;
if(t[2]>0)
f[2][t[1]][t[2]-1][t[3]][t[4]][t[5]]=
p[2][t[1]][t[2]-1][t[3]][t[4]][t[5]]=1.0*t[2]/tmp;
if(t[3]>0)
f[3][t[1]][t[2]][t[3]-1][t[4]][t[5]]=
p[3][t[1]][t[2]][t[3]-1][t[4]][t[5]]=1.0*t[3]/tmp;
if(t[4]>0)
f[4][t[1]][t[2]][t[3]][t[4]-1][t[5]]=
p[4][t[1]][t[2]][t[3]][t[4]-1][t[5]]=1.0*t[4]/tmp;
if(t[5]>0)
f[5][t[1]][t[2]][t[3]][t[4]][t[5]-1]=
p[5][t[1]][t[2]][t[3]][t[4]][t[5]-1]=1.0*t[5]/tmp;
for(int sum=tmp-1;sum>=1;sum--)
for(int i=1;i<=5;i++)
for(a[1]=sum-t[2]-t[3]-t[4]-t[5],a[1]=a[1]<0?0:a[1];a[1]<=t[1]-(i==1)&&a[1]<=sum;a[1]++)
for(a[2]=sum-a[1]-t[3]-t[4]-t[5],a[2]=a[2]<0?0:a[2];a[2]<=t[2]-(i==2)&&a[1]+a[2]<=sum;a[2]++)
for(a[3]=sum-a[1]-a[2]-t[4]-t[5],a[3]=a[3]<0?0:a[3];a[3]<=t[3]-(i==3)&&a[1]+a[2]+a[3]<=sum;a[3]++)
for(a[4]=sum-a[1]-a[2]-a[3]-t[5],a[4]=a[4]<0?0:a[4];a[4]<=t[4]-(i==4)&&a[1]+a[2]+a[3]+a[4]<=sum;a[4]++)
{
a[5]=sum-a[1]-a[2]-a[3]-a[4];
// printf("%d %d %d %d %d\n",a[1],a[2],a[3],a[4],a[5]);
if(i==5&&a[5]==t[5]) continue;
double tf=f[i][a[1]][a[2]][a[3]][a[4]][a[5]];
double tp=p[i][a[1]][a[2]][a[3]][a[4]][a[5]];
// printf("%lf %lf %d\n",tf,tp,sum);
tf/=tp,tp/=sum;
if(tp==0) continue;
if(a[1]>0)
{
f[1][a[1]-1][a[2]][a[3]][a[4]][a[5]]+=(tf+(i!=1))*tp*a[1];
p[1][a[1]-1][a[2]][a[3]][a[4]][a[5]]+=tp*a[1];
}
if(a[2]>0)
{
f[2][a[1]][a[2]-1][a[3]][a[4]][a[5]]+=(tf+(i!=2))*tp*a[2];
p[2][a[1]][a[2]-1][a[3]][a[4]][a[5]]+=tp*a[2];
}
if(a[3]>0)
{
f[3][a[1]][a[2]][a[3]-1][a[4]][a[5]]+=(tf+(i!=3))*tp*a[3];
p[3][a[1]][a[2]][a[3]-1][a[4]][a[5]]+=tp*a[3];
}
if(a[4]>0)
{
f[4][a[1]][a[2]][a[3]][a[4]-1][a[5]]+=(tf+(i!=4))*tp*a[4];
p[4][a[1]][a[2]][a[3]][a[4]-1][a[5]]+=tp*a[4];
}
if(a[5]>0)
{
f[5][a[1]][a[2]][a[3]][a[4]][a[5]-1]+=(tf+(i!=5))*tp*a[5];
p[5][a[1]][a[2]][a[3]][a[4]][a[5]-1]+=tp*a[5];
}
}
double ans=0;
for(int i=1;i<=5;i++)
ans+=f[i][0][0][0][0][0];
printf("%.18lf",ans);
}
题解:造出最短路树,然后树上倍增;
\(code:\)
#include<cstdio>
#include<algorithm>
#include<ctype.h>
#include<vector>
#include<queue>
#include<cstring>
#define lowbit(x) (x&-x)
#define ll long long
#define ld double
#include<map>
#define inf 1e9+9
#include<stdlib.h>
#include<ctime>
using namespace std;
char buf[1<<20],*p1,*p2;
inline char gc()
{
// return getchar();
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}
template<typename T>
inline void read(T &x)
{
char tt;
bool flag=0;
while(!isdigit(tt=gc())&&tt!='-');
tt=='-'?(flag=1,x=0):(x=tt-'0');
while(isdigit(tt=gc())) x=x*10+tt-'0';
if(flag) x=-x;
}
struct node{
int x,len;
inline node(int a=0,int b=0)
{x=a,len=b;}
inline bool operator<(node a)const
{return len>a.len;}
};
const int maxn=100002;
int n,m,que;
int log_[maxn],fa[maxn][20],f[maxn][20],dep[maxn];
int dis1[maxn],dis2[maxn];
vector<node>G[maxn],g[maxn];
void djs1()
{
priority_queue<node>q;
for(int i=1;i<=n;i++) dis1[i]=inf;
dis1[1]=0;q.push(node(1,0));
while(!q.empty())
{
int x=q.top().x;
int len=q.top().len;q.pop();
if(dis1[x]!=len) continue;
for(int i=G[x].size()-1;i>=0;i--)
{
int p=G[x][i].x;
len=G[x][i].len;
if(dis1[p]<=dis1[x]+len) continue;
dis1[p]=dis1[x]+len;
q.push(node(p,dis1[p]));
}
}
}
void djs2()
{
priority_queue<node>q;
for(int i=1;i<=n;i++) dis2[i]=inf;
dis2[n]=0;q.push(node(n,0));
while(!q.empty())
{
int x=q.top().x;
int len=q.top().len;q.pop();
if(dis2[x]!=len) continue;
for(int i=g[x].size()-1;i>=0;i--)
{
int p=g[x][i].x;
len=g[x][i].len;
if(dis2[p]<=dis2[x]+len) continue;
dis2[p]=dis2[x]+len;
q.push(node(p,dis2[p]));
}
}
for(int i=1;i<=n;i++) f[i][0]=dis2[i];
}
void bfs()
{
queue<int>q;q.push(1);
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=1;i<=log_[n];i++)
if(fa[x][i-1])
fa[x][i]=fa[fa[x][i-1]][i-1],f[x][i]=min(f[fa[x][i-1]][i-1],f[x][i-1]);
else break;
for(int i=G[x].size()-1;i>=0;i--)
{
int p=G[x][i].x;
int len=G[x][i].len;
if(dis1[p]!=dis1[x]+len) continue;
dep[p]=dep[x]+1,fa[p][0]=x;q.push(p);
}
}
}
void solve1(int x,int y)//深度
{
int ans=inf;
if(dep[x]<y){puts("-1");return;}
for(int i=log_[n];i>=0;i--)
if(dep[fa[x][i]]>=y)
ans=min(f[x][i],ans),
x=fa[x][i];
ans=min(ans,f[x][0]);
printf("%d\n",ans);
}
void solve2(int x,int y)//长度
{
int ans=inf;
if(dis1[x]<y){puts("-1");return;}
for(int i=log_[n];i>=0;i--)
if(dis1[fa[x][i]]>=y)
ans=min(f[x][i],ans),
x=fa[x][i];
ans=min(ans,f[x][0]);
printf("%d\n",ans);
}
int main()
{
read(n),read(m),read(que);log_[0]=-1;
for(int i=1;i<=n;i++) log_[i]=log_[i>>1]+1;
for(int i=1;i<=m;i++)
{
int x,y,len1,len2;
read(x),read(y),read(len1),read(len2);
G[x].push_back(node(y,len1));
G[y].push_back(node(x,len1));
g[x].push_back(node(y,len2));
g[y].push_back(node(x,len2));
}
djs1();djs2();bfs();dep[0]=-1,dis1[0]=-1;
while(que--)
{
int opt,x,y;
read(opt),read(x),read(y);
if(opt==1) solve1(x,y);
if(opt==2) solve2(x,y);
}
}