您的位置:首页 > 其它

【洛谷 1357】 花园

2016-03-10 19:01 399 查看
“<<” 的运算优先级低于 ‘+’!!!

貌似对矩阵理解更深刻了!

以下题解摘自网络

2<=M<=5,相邻的M个花圃可能有2^M种状态 ,用0~2^M-1来表示

要求有不超过K个C形花圃,对应其二进制形式中的0不超过K个。

标记出0~2^M-1中满足条件的状态x,

对于每个状态x,前M个花圃会出现1次

f(i,x)表示前i个花圃中,最后M个花圃的状态是x的方案数。

例:N=6,M=2,K=1

x取01,10,11

f(2,01)增加1个花圃,可以得到状态f(3,10)和f(3,11)

f(2,10)增加1个花圃,可以得到状态f(3,01)

f(2,11)增加1个花圃,可以得到状态f(3,10)和f(3,11)

花圃围成一圈,要使任意相邻的M个都满足要求,

对于每个状态x,由f(M,x)出发,求f(N+M,x)即可

再累加求得结果。

状态x增加1位后可能产生的状态:

x%2^(m-1)2, x%2^(m-1)2+1

复杂度:O(N)

40%的数据中,N<=20;

60%的数据中,M=2;

80%的数据中,N<=10^5。

100%的数据中,N<=10^15。 会超时。

加速优化:

考虑状态x从何而来?

x/2 和 x/2+2^(M-1)

例:M=5,K=3,状态00111 可以由 00011 和 10011 再加一个1得到。

用矩阵乘法来实现:

N=6,M=2,K=1,

(1 1 0 0)

(f(m,00) f(m,01) f(m,10) f(m,11)) * (0 0 1 1)

(1 1 0 0)

(0 0 1 1)

利用矩阵乘法快速幂优化加速。

#include <cstdio>
#include <cstring>
#define MO 1000000007
#define LL long long
LL n,m,k,N;
LL a[40][40],b[40][40],tmp[40][40];
int can[40];
inline void F(LL fo[][40],LL to[][40])
{
memset(tmp,0,sizeof(tmp));
for(int i=0;i<=N;i++)
for(int j=0;j<=N;j++)
for(int k=0;k<=N;k++)
tmp[i][j]=(fo[i][k]*to[k][j]+tmp[i][j])%MO;
for(int i=0;i<=N;i++)
for(int j=0;j<=N;j++)
to[i][j]=tmp[i][j];
}
int main()
{
scanf("%lld %lld %lld",&n,&m,&k);
N=(1<<m)-1;
for(int i=0;i<=N;i++)
{
int cnt=0,x=i;
while(x!=0)
{
if(x&1==1) cnt++;
x>>=1;
}
if(cnt<=k)
{
can[i]=true;
a[i>>1][i]=1;
a[(i>>1)+(1<<(m-1))][i]=1;
}
b[i][i]=1;
}
while(n!=1)
{
if(n%2==1) F(a,b);
F(a,a);
n>>=1;
}
F(a,b);
LL ans=0;
for(int i=0;i<=N;i++)
if(can[i])
ans+=b[i][i],ans%=MO;
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: