2018.10.06 练习赛

T1 Too Young

题解:

设状态\(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]);
}

T2 Too Simple

题解:(暂未做,copy出题人原话)

一个状态应该包含,每种颜色的剩余数量,以及当前画的最后一笔的颜色。

所以状态就是\(f[k][(i_1...,i_n)]\)表示最后一笔颜色为k,各颜色还剩.... in支的时候,颜色段数的期望值。

这样并不能递推,还缺一个辅助的状态\(p[k][(i_1,...i_n)]\), 表示到达当前状态的概率。

\((std)code:\)

#include <cstdio>
#include <cstdlib>
using namespace std;
int N,A,a[10];
double f[5][16][16][16][16][16],p[5][16][16][16][16][16];
int main()
{
    freopen("B.in","r",stdin);
    freopen("B.out","w",stdout);
    int i,j,k,i0,i1,i2,i3,i4;
    double tf,tp;
    scanf("%d",&N);
    for(i=0;i<N;i++)
    {
        scanf("%d",&a[i]);
        A+=a[i];
    }
    if(a[0]>0)
        f[0][a[0]-1][ a[1] ][ a[2] ][ a[3] ][ a[4] ]=
        p[0][a[0]-1][ a[1] ][ a[2] ][ a[3] ][ a[4] ]=1.0*a[0]/A;
    if(a[1]>0)
        f[1][ a[0] ][a[1]-1][ a[2] ][ a[3] ][ a[4] ]=
        p[1][ a[0] ][a[1]-1][ a[2] ][ a[3] ][ a[4] ]=1.0*a[1]/A;
    if(a[2]>0)
        f[2][ a[0] ][ a[1] ][a[2]-1][ a[3] ][ a[4] ]=
        p[2][ a[0] ][ a[1] ][a[2]-1][ a[3] ][ a[4] ]=1.0*a[2]/A;
    if(a[3]>0)
        f[3][ a[0] ][ a[1] ][ a[2] ][a[3]-1][ a[4] ]=
        p[3][ a[0] ][ a[1] ][ a[2] ][a[3]-1][ a[4] ]=1.0*a[3]/A;
    if(a[4]>0)
        f[4][ a[0] ][ a[1] ][ a[2] ][ a[3] ][a[4]-1]=
        p[4][ a[0] ][ a[1] ][ a[2] ][ a[3] ][a[4]-1]=1.0*a[4]/A;
    for(j=A-1;j>=1;j--)
    for(k=0;k<=4;k++)
    for(i0=j-a[1]-a[2]-a[3]-a[4],i0=i0<0?0:i0;i0<=a[0]-(k==0)&&i0         <=j;i0++)
    for(i1=j- i0 -a[2]-a[3]-a[4],i1=i1<0?0:i1;i1<=a[1]-(k==1)&&i0+i1      <=j;i1++)
    for(i2=j- i0 - i1 -a[3]-a[4],i2=i2<0?0:i2;i2<=a[2]-(k==2)&&i0+i1+i2   <=j;i2++)
    for(i3=j- i0 - i1 - i2 -a[4],i3=i3<0?0:i3;i3<=a[3]-(k==3)&&i0+i1+i2+i3<=j;i3++)
    {
        i4=j-i0-i1-i2-i3;
        if(k==4&&i4==a[4])continue;
        tf=f[k][i0][i1][i2][i3][i4];
        tp=p[k][i0][i1][i2][i3][i4];
        tf/=tp;tp/=j;
        if(tp==0)continue;
        if(i0>0)
            f[0][i0-1][ i1 ][ i2 ][ i3 ][ i4 ]+=(tf+(k!=0))*tp*i0,
            p[0][i0-1][ i1 ][ i2 ][ i3 ][ i4 ]+=tp*i0;
        if(i1>0)
            f[1][ i0 ][i1-1][ i2 ][ i3 ][ i4 ]+=(tf+(k!=1))*tp*i1,
            p[1][ i0 ][i1-1][ i2 ][ i3 ][ i4 ]+=tp*i1;
        if(i2>0)
            f[2][ i0 ][ i1 ][i2-1][ i3 ][ i4 ]+=(tf+(k!=2))*tp*i2,
            p[2][ i0 ][ i1 ][i2-1][ i3 ][ i4 ]+=tp*i2;
        if(i3>0)
            f[3][ i0 ][ i1 ][ i2 ][i3-1][ i4 ]+=(tf+(k!=3))*tp*i3,
            p[3][ i0 ][ i1 ][ i2 ][i3-1][ i4 ]+=tp*i3;
        if(i4>0)
            f[4][ i0 ][ i1 ][ i2 ][ i3 ][i4-1]+=(tf+(k!=4))*tp*i4,
            p[4][ i0 ][ i1 ][ i2 ][ i3 ][i4-1]+=tp*i4;
    }
    tf=0;
    for(i=0;i<N;i++)
        tf+=f[i][0][0][0][0][0];
    printf("%.10lf\n",tf);
    return 0;
}

T3 Sometimes Naive

题解:

正反跑一遍最短路(第一次跑从起点带女朋友的,第二次跑从终点自己跑的)

在正向最短路生成的最短路树上跑\(bfs\),记录\(fa1[i][j]\),表示\(i\)的第\(1<<j\)个父亲,记录\(fa2[i][j]\),表示\(i\)点到\(1<<j\)个父亲中,单独回家的最小值,倍增处理一下.\(bfs\)时判断是否是最短路上的点,然后加入队列更新就行了

\(code:\)

#include<stdio.h>
#include<algorithm>
#include<queue> 
#include<string.h>
#include<ctype.h>
#define inf 1e9+9
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';
}

struct node{
    int x,len;
    inline node(int a,int b)
    {
        x=a;
        len=b;
    }
    inline bool operator<(node a)const
    {
        return len>a.len;
    }
};

int n,m,tot,t,maxn;
int dep[100005];
int dis1[100005],dis2[100005];
int fa1[100005][20],fa2[100005][20];
vector<node>G[100005][2];
priority_queue<node>q;
queue<int>qq;

void djs1()
{
    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(len!=dis1[x]) continue;
        for(int i=G[x][0].size()-1;i>=0;i--)
        {
            int p=G[x][0][i].x;
            len=G[x][0][i].len;
            if(dis1[p]<=dis1[x]+len) continue;
            dis1[p]=dis1[x]+len;
            q.push(node(p,dis1[p]));
        }
    }
}

void djs2()
{
    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(len!=dis2[x]) continue;
        for(int i=G[x][1].size()-1;i>=0;i--)
        {
            int p=G[x][1][i].x;
            len=G[x][1][i].len;
            if(dis2[p]<=dis2[x]+len) continue;
            dis2[p]=dis2[x]+len;
            q.push(node(p,dis2[p]));
        }
    }
}

void bfs()
{
    qq.push(1);
    while(!qq.empty())
    {
        int x=qq.front();
        qq.pop();
        for(int j=1;j<=maxn;j++)
        {
            fa1[x][j]=fa1[fa1[x][j-1]][j-1];
            fa2[x][j]=min(fa2[fa1[x][j-1]][j-1],fa2[x][j-1]);
        }
        for(int i=G[x][0].size()-1;i>=0;i--)
        {
            int p=G[x][0][i].x;
            int len=G[x][0][i].len;
            if(dis1[p]==dis1[x]+len)
            {
                fa1[p][0]=x;
                dep[p]=dep[x]+1;
                qq.push(p);
            }
        }
    }
}

void solve1(int x,int y)//街道 
{
    int ans=inf;
    if(dep[x]<y)
    {
        puts("-1");
        return;
    }
    for(int i=maxn;i>=0;i--)
    if(dep[fa1[x][i]]>=y)
    {
        ans=min(ans,fa2[x][i]);
        x=fa1[x][i];
    }
    ans=min(ans,fa2[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=maxn;i>=0;i--)
    if(dis1[fa1[x][i]]>=y)
    {
        ans=min(ans,fa2[x][i]);
        x=fa1[x][i];
    }
    ans=min(ans,fa2[x][0]);
    printf("%d\n",ans);
}

int main()
{
    read(n),read(m),read(t);
    while(n>>maxn)maxn++;maxn--;
    for(int i=1;i<=m;i++)
    {
        int x,y,len1,len2;
        read(x),read(y),read(len1),read(len2);
        G[x][0].push_back(node(y,len1));
        G[y][0].push_back(node(x,len1));
        
        G[x][1].push_back(node(y,len2));
        G[y][1].push_back(node(x,len2));
    }
    djs1();// 1
    djs2();// n
    for(int i=1;i<=n;i++) fa2[i][0]=dis2[i];
    bfs();
    dis1[0]=-1;dep[0]=-1;
    while(t--)
    {
        int k,x,y;
        read(k),read(x),read(y);
        if(k==1) solve1(x,y);
        if(k==2) solve2(x,y);
    }
}

猜你喜欢

转载自www.cnblogs.com/KatouKatou/p/9749010.html
今日推荐