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的主要内容,如果未能解决你的问题,请参考以下文章