2019.9.10

Posted iwillenter-top1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019.9.10相关的知识,希望对你有一定的参考价值。

(1.bzoj) (1008) 越狱

题意:

(n)个位置,(m)种数,每个位置填一个数,使得有相邻两位置的数相同,问有多少种方案。每种数的个数都是无限的。

分析:

明显的排列组合问题

我们现在先不考虑相邻位置的数相同的条件,则一共有
[ m^n ]
种方案,再减去每个相邻位置的数都不相同的方案总数。

怎么算呢?

第一个人有m种选择,第二个人因为要与第一个人不同,故有m-1种选择

第三个人因为要与第二个人不同,故有m-1(除去第二个人的那个数)

...

第n个人有m-1种选择,故共有
[ m^n-m*(m-1)^{n-1} ]
种方案

(Code:)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define ll long long

const int mod=1e5+3;
ll fpow(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=(ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return ans;
}
int main()
{
    ll n,m;
    scanf("%lld%lld",&m,&n);//注意输入顺序
    ll res=(fpow(m,n)-m*fpow(m-1,n-1))%mod;
    while(res<mod) res+=mod;//要注意负数的处理
    printf("%d
",res%mod);
}

收获:补集转化,数学分析,快速幂

(2.bzoj) (1009) (GT)的考试

题意:

阿申准备报名参加(GT)考试,准考证号为(N)位数(X1X2....Xn(0<=Xi<=9)),他不希望准考证号上出现不吉利的数字。他的不吉利数学(A1A2...Am(0<=Ai<=9))有M位,不出现是指(X1X2...Xn)中没有恰好一段等于(A1A2...Am.) (A1)(X1)可以为(0)

分析:

首先可以发现这是一个动态规划的题,我们设(f(i,j))表示前i个字符匹配到了不吉利字符的第(j)位的方案数,则答案为
[ ans=sum_{j=0}^{M-1}f[n][j] ]
为什么是到(M-1)呢?因为我们不能出现不吉利数字。

这样一个字符串匹配,让我们很容易想到(kmp)或者(AC)自动机,由于它只有一个匹配串和一个文本串,没必要用(AC)自动机,用(kmp)就可以了

(f(i,j))可以转移到(1).(f(i+1,j+1)2.f(i+1,next[j]+1)3.f(i+1,0))

而:
[ f[i][j]=sum_{k=0}^{M-1} f[i-1][k]*a[k][j] ]
怎么算(a(k,j))呢?我们枚举在准考证上第(i+1)位可能出现的字符,然后看(f(i,j))能转移到哪里去,接着就在转移矩阵上的这个转移路径上(+1)

这样的形式非常像矩阵乘法,再看看我们的数据范围(n<=1e9),所以我们要使用矩阵快速幂来优化

为什么可以用矩阵快速幂来优化呢?因为
[ sum_{k=0}^{M-1}a[k][j] ]
是一个定值,所以我们预处理出这部分.
[ f(i,j)=f(i-1,0)*a(0,j)+f(i-1,1)*a(1,j)+f(i-1,2)*a(2,j)... ]
我们发现a的列数都是相同的,所以把f数组也抽象为一个矩阵
[ (f[i][0]quad f[i][1]quad...)=(f[i-1][0]quad f[i-1][1]quad...)* left( egin{matrix} a_{00}&quad a_{01}...a_{10}&quad a_{11}...\cdotsa_{m-10}&quad a_{m-11}...\end{matrix} ight) ]
用矩阵快速幂优化即可
[ (f[n][0]quad f[n][1]quad...)=(f[0][0]quad f[0][1]quad...)* left( egin{matrix} a_{00}&quad a_{01}...a_{10}&quad a_{11}...\cdotsa_{m-10}&quad a_{m-11}...\end{matrix} ight)^{n} ]
不过下面的代码,行和列是反着写的

(Code:)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;

int a[25][25],f[25][25];
char s[25][25];
int n,m;
int mod;
int nxt[maxn];

void mul(int b[25][25],int c[25][25],int d[25][25])
{
    int tmp[25][25];
    for(int i=0;i<m;++i)
    {
        for(int j=0;j<m;++j)
        {
            tmp[i][j]=0;
            for(int k=0;k<m;++k)
            {
                tmp[i][j]=(tmp[i][j]+b[i][k]*c[k][j])%mod;
            }
        }
    }
    for(int i=0;i<m;++i)
    {
        for(int j=0;j<m;++j)
        {
            d[i][j]=tmp[i][j];
        }
    }
}
template<class T>void read(T &x)
{
    bool f=0;char ch=getchar();x=0;
    for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    if(f) x=-x;
}
int main()
{
    read(n);read(m);read(mod);
    scanf("%s",s+1);
    for(int i=2,j=0;i<=m;++i)
    {
        while(j&&s[i]!=s[j+1]) j=nxt[j];
        if(s[i]==s[j+1]) ++j;
        nxt[i]=j;
    }
    for(int i=0;i<m;++i)
    {
        for(int j=0;j<=9;++j)
        {
            int t=i;
            while(t&&s[t+1]!=j) t=nxt[t];
            if(s[t+1]-'0'==j) ++t;
            if(t<m) a[t][i]=(a[t][i]+1)%mod;//这里的行和列与我们定义的是相反的,这里是指从i转
        }                                  //移到t所有的方案数
    }
    for(int i=0;i<m;++i) f[i][i]=1;
    while(n)//矩阵快速幂加速
    {
        if(n&1) mul(f,a,f);
        mul(a,a,a);
        n>>=1;
    }
    int ans=0;
    for(int i=0;i<m;++i) ans=(ans+f[i][0])%mod;
    printf("%d
",ans);
    return 0;
}

完了?

以上是关于2019.9.10的主要内容,如果未能解决你的问题,请参考以下文章

2019.9.10

2019.9.10 6.828 barrier

校内模拟赛(2019.9.10)

2019.9.10计算机基本硬件知识

2019阅读书单

微信小程序代码片段