[补档]noip2019集训测试赛(十二)

Problem A: 记忆(memory)

Time Limit: 1000 ms Memory Limit: 512 MB

Description

你在跟朋友玩一个记忆游戏。

朋友首先给你看了n个长度相同的串,然后从中等概率随机选择了一个串。

每一轮你可以询问一个位置上的正确字符,如果能够凭借已有的信息确定出朋友所选的串,那么游戏就结束了,你的成绩就是所用的轮数。

由于你实在太笨,不会任何策略,因此你采用一种方法,每次等概率随机询问一个未询问过的位置的字符。

现在你想知道,在这种情况下,你猜出结果所需的期望次数。

Input

第1行包含一个整数 n,表示串的个数。

第 2 ~ n+1行每行包含一个长度相等的字符串,仅包含小写字母和大写字母。

Output

输出1行一个小数,表示猜出结果所需的期望次数,保留10位小数。

Sample Input

3
aaA
aBa
Caa

Sample Output

1.6666666667

HINT

设串长为l

对于20%的数据, n,l≤10

对于30%的数据, n,l≤15

对于60%的数据, n,l≤20

对于100%的数据, n≤50,l≤20

Solution

期望DP

考虑状压,a[i][j]表示在第i位上为字符j的个数,这个个数用一个二进制状态表示,第k位是1即表示k串第i位是字符j。

设b[i][j]代表在询问状态为j且答案为i的情况下,还有b[i][j]个字符串满足要求,同样以二进制状态储存。

设num[i],表示在询问状态为i的情况下,有num[i]个满足条件的字符串。

设i代表答案为第i个字符串,j代表当前询问状态,不难得到转移方程:

\(设k=j \bigoplus lowbit(j),pos为lowbit的位置\)

$ b[i][j] = b[i][k] and a[pos][s[i][pos]] $

\(num[j]+=[b[i][j]!=lowbit(b[i][j])]\)

第二条含义:如果pos位置上等于s[i][pos]的字符串同时也满足询问k的条件,显然它在询问j状态下也是满足的

第三条含义:如果有不确定的情况,那么num[j]++

接下来我们用cnt[i]表示二进制下i的1的个数,f[i]表示转移到状态i的概率

设\(tmp=f[i \bigoplus (1<<j)]/(m-cnt[i \bigoplus (1<<j)])\),这代表了从\(i \bigoplus (1<<j)\)转移到i的概率(即1/上一状态的0的个数)

所以有\(f[i]+=tmp\)

接下来,我们有\(ans+=cnt[i]*(tmp*(num[i \bigoplus (1<<j)]-num[i]))\),这是什么意思呢?

首先cnt[i]是转移到i状态的操作个数(就是1的个数)

后面的tmp乘上的那一坨玩意儿就意味着你可以从\(num[i \bigoplus (1<<j)]-num[i]\)这些从不确定转为确定状态的串中任意一个进行转移

于是最后统计出来的ans就是所有串被猜中的期望操作次数总和

除以n就是最后答案了

#include<bits/stdc++.h>
using namespace std;
int n,m,M;
const int N=1<<20;
int num[N],cnt[N],s[50][20];
long long a[50][52],b[50][N];
long double f[N],ans;
char str[20];
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%s",str);
        m=strlen(str),M=1<<m;
        for(int j=0;j<m;j++){
            s[i][j]=('a'<=str[j]&&str[j]<='z')?str[j]-'a':str[j]-'A'+26;
            a[j][s[i][j]]|=(1ll<<i);
        }
    }
    num[0]=n;
    for(int i=0;i<n;i++){
        b[i][0]=(1LL<<n)-1LL;
        for(int j=1;j<M;j++){
            int k=j^(j&-j);
            int pos=__builtin_ctz(j);
            b[i][j]=b[i][k]&a[pos][s[i][pos]];
            if(b[i][j]!=(b[i][j]&-b[i][j])) num[j]++;
        }
    }
    for(int i=1;i<M;i++)
    cnt[i]=cnt[i>>1]+(i&1);
    f[0]=1;
    for(int i=1;i<M;i++)
    for(int j=0;j<m;j++)
    if((i>>j)&1){
        long double tmp=f[i^(1<<j)]/(m-cnt[i^(1<<j)]);
        ans+=cnt[i]*(tmp*(num[i^(1<<j)]-num[i]));
        f[i]+=tmp;
    }
    printf("%.10Lf",ans/n);
}

Problem B: 神经元(neuron)

Time Limit: 1000 ms Memory Limit: 512 MB

Description

你培育出了一些新型的神经元,它们可以有很多的轴突。

具体来说,对于第i个神经元,它有1~di条轴突,因此可以与1~di个神经元相连,可以将轴突看成无向图的边,假定每个神经元都是不同的。

现在你想知道,有多少种方案使得其中恰好k个神经元相连通,这里的连通需要保证任意两个神经元间有且仅有一条路径,方案数可能很大,你只需要对10^9+7取模输出。

两个方案是不同的当且仅当选择的神经元集合不同或其中有至少一条轴突(u,v)出现在一个方案但不出现在另一个方案。

Input

第1行包含一个整数n,表示神经元的个数。

第2行包含n个整数di,表示第i个神经元最多的轴突数量(1<=di<n)。

Output

输出1行,包含n个整数,第i个整数表示其中恰好有i个神经元连通的方案数模 10^9+7后的值。

Sample Input

3
2 2 1 

Sample Output

3 3 2

HINT

对于10%的数据,n<=8

对于另外10%的数据,di=n-1

对于20%的数据,n<=15

对于30%的数据,n<=20

对于40%的数据,n<=50

对于60%的数据,n<=70

对于100%的数据,n<=100

Solution

不知道哪儿来那么多部分分

prufer序列上的dp

prufer序列:无根树所对应的一种序列,任何一种无根树形态都对应着一个prufer序列,没有重复者。一棵无根树的长度是点数-2。可以百度了解一下。

设dp[i][j][k]表示前i个点,选择了j个点来构成这棵树,prufer长度为k的情况(显然出现环时prufer序列就不会是n-2那么长了)

分两类讨论:

1、不选这个点 \(dp[i+1][j][k]+=dp[i][j][k]\)

2、选择这个点 我们枚举这个点伸出来的边数l

可以得到\(dp[i+1][j+1][k+l]+=dp[i][j][k]*C[k+l][l]\),其中C数组代表组合

即他可以选择在k+l长度的prufer序列中,任意选择l个位置让自己出现(因为每一种prufer序列都对应着不同的树的形态,所以显然prufer序列种数就是树构成的方案树)

最后输出的就是dp[n][i][i-2]了。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define mod (int)(1e9+7)
int C[201][201];
void pre(){
    for(int i=0;i<=200;++i){
        C[i][0]=1;
        for(int j=1;j<=i;++j){
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
        }
    }
}
int a[201];
int dp[201][201][201];
signed main(){
    pre();
    int n;
    scanf("%lld",&n);
    for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
    dp[0][0][0]=1;
    for(int i=0;i<n;++i){
        for(int j=0;j<=i;++j){
            for(int k=0;k<=n-2;++k){
                if(!dp[i][j][k])continue;
                dp[i+1][j][k]=(dp[i+1][j][k]+dp[i][j][k])%mod;
                for(int l=0;l<a[i+1]&&k+l<=n-2;++l){
                    dp[i+1][j+1][k+l]=(dp[i+1][j+1][k+l]+dp[i][j][k]*C[k+l][l])%mod;
                }
            }
        }
    }
    printf("%lld ",n);
    for(int i=2;i<=n;++i){
        printf("%lld ",dp[n][i][i-2]);
    }
}

原文地址:https://www.cnblogs.com/youddjxd/p/11434297.html

时间: 2024-10-13 00:14:18

[补档]noip2019集训测试赛(十二)的相关文章

[补档]noip2019集训测试赛(十五)

Problem A: 传送带 Time Limit: 1000 ms Memory Limit: 256 MB Description 在一个二维平面上有两条传送带,每一条传送带可以看成是一条线段.两条传送带分别为线段AB和线段CD.小y在AB上的移动速度为P,在CD上的移动速度为Q,在平面上的移动速度R.现在,小y想从A点走到D点,请问他最少需要走多长时间. Input 第一行是4个整数,表示A和B的坐标,分别为Ax,Ay,Bx,By. 第二行是4个整数,表示C和D的坐标,分别为Cx,Cy,D

[补档]noip2019集训测试赛(八)

Problem B: 2048 Special Judge Time Limit: 1000 ms Memory Limit: 256 MB Description 2048曾经是一款风靡全球的小游戏. 今天,我们换一种方式来玩这个小游戏. 现在,你有一个双端队列,你只能把元素从左端或从右端放入双端队列中.一旦放入就不得取出.放入后,若队列中有连续两个相同的元素,它们将自动合并变成一个新的元素--原来那两个元素的和.若新的元素与它相邻的元素相同,则继续合并-- 如:双端队列中有2, 4, 16三

noip2019集训测试赛(二)

Problem A: 余数 Time Limit: 1000 ms Memory Limit: 512 MB Description Input Output Sample Input 3 4 Sample Output 4 HINT Solution 那个所谓\(\sqrt n\)的东西叫做整除分块. 显然对于\(n÷i\),当$i<=\sqrt n $时,每个i都有一种取法 当\(n>=i>\sqrt n\),i每加\(\sqrt n\),\(n÷i\)的值就+1 然后就可以根号时间

2016集训测试赛(二十五)小结

这场测试赛有必要小结一下. 昨晚 1 点才睡, 今天状态很差, 先睡了 1 个小时, 然后开始打比赛. 第一题不大会做, 写了一个代码后发现是错的, 第二题看不懂题, 第三题简单地分析了一下, 发现是一个树形DP . 然后做 T3 , 大概推了很久, 写了很久, 又写了几个对拍, 搞到 11 点才搞掂. 这时候我发现 T1 有 50 分是我可做的, 然后 T2 的题意仍然不是很明确, 我想尝试着写写 T2 , 这个必须要写出来才能看出题意是不是这样, 写着写着发现 T2 的题意不是我理解的这样,

noip2019集训测试赛(四)

Problem A: fibonacci Time Limit: 3000 ms Memory Limit: 256 MB Description Input 第一行两个数 N,M . 第二行 N 个数 a1,a2,...,an . 接下来 M 行, 每行代表题目描述中的一种操作. Output 对于每个询问, 输出一行, 表示答案. Sample Input 5 4 1 1 2 1 1 2 1 5 1 2 4 2 2 2 4 2 1 5 Sample Output 5 7 9 HINT 对于

noip2019集训测试赛(七)

Problem A: Maze Time Limit: 1000 ms Memory Limit: 256 MB Description 考虑一个N×M的网格,每个网格要么是空的,要么是障碍物.整个网格四周都是墙壁(即第1行和第n行,第1列和第m列都是墙壁),墙壁有且仅有两处开口,分别代表起点和终点.起点总是在网格左边,终点总是在网格右边.你只能朝4个方向移动:上下左右.数据保证从起点到终点至少有一条路径. 从起点到终点可能有很多条路径,请找出有多少个网格是所有路径的必经网格. Input 第一

Welcome to Swift (苹果官方Swift文档初译与注解十二)---77~83页(第二章)

Optionals (可选类型) 当一个值可能有值,也可能没有值,这种情况你可以使用可选类型.可选类型的意思是: 有个一个值,它等于x,或者,根本没有任何值. 注意点: 可选类型的概念在C和OC中都是没有的.在OC中最相似的情况是,一个方法返回nil或者返回一个对象.OC中返回nil意思是没有合法的对象.然而,这只能针对对象,不能用在结构体,基本 数据类型,或者枚举值.对于这些类型,OC的方法只能返回固定的某个值(比如NSNotFound)来提示没有某个值.这要去方法的调用者清楚的记得返回的固定

Kali Linux Web 渗透测试— 第十二课-websploit

Kali Linux Web 渗透测试— 第十二课-websploit 文/玄魂 目录 Kali Linux Web 渗透测试— 第十二课-websploit............................................... 1 Websploit 简介........................................................................................... 2 主要功能...........

【2016北京集训测试赛(八)】 crash的数列

Description 题解 题目说这是一个具有神奇特性的数列!这句话是非常有用的因为我们发现,如果套着这个数列的定义再从原数列引出一个新数列,它居然还是一样的...... 于是我们就想到了能不能用多点数列套着来加速转移呢? 但是发现好像太多数列套起来是可以烦死人的...... 我们就采用嵌套两次吧,记原数列为A,第一层嵌套为B,第二层嵌套为C. 我们其实可以发现一些规律,对于Ci,它对应了B中i的个数:对于Bi,它对应了A中i的个数. 稍加处理即可,我们一边计算一边模拟数列的运算,同时可以计算