bzoj 2004(状压+矩阵)

2004: [Hnoi2010]Bus 公交线路

Time Limit: 20 Sec   Memory Limit: 259 MB
Submit: 576   Solved: 406
[ Submit][ Status][ Discuss]

Description

小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km。 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计线路: 1. 设共K辆公交车,则1到K号站作为始发站,N-K+1到N号台作为终点站。 2. 每个车站必须被一辆且仅一辆公交车经过(始发站和终点站也算被经过)。 3. 公交车只能从编号较小的站台驶往编号较大的站台。 4. 一辆公交车经过的相邻两个站台间距离不得超过Pkm。 在最终设计线路之前,小Z想知道有多少种满足要求的方案。由于答案可能很大,你只需求出答案对30031取模的结果。

Input

仅一行包含三个正整数N K P,分别表示公交车站数,公交车数,相邻站台的距离限制。N<=10^9,1<P<=10,K<N,1<K<=P

Output

仅包含一个整数,表示满足要求的方案数对30031取模的结果。

Sample Input

样例一:10 3 3
样例二:5 2 3
样例三:10 2 4

Sample Output

1
3
81

HINT

【样例说明】

样例一的可行方案如下: (1,4,7,10),(2,5,8),(3,6,9)

样例二的可行方案如下: (1,3,5),(2,4) (1,3,4),(2,5) (1,4),(2,3,5) 

P<=10 , K <=8

解题思路:因为状态不多,所以将m+1看成一个整体,然后
枚举出所用可能的情况(dfs)并且状压记录下那些状态可以到哪个状态建立矩阵,
然后矩阵快速幂就可以了。
(细节坑死了。。。)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m,k,cnt,ans,uoo,sug,pu;
const int MOD=30031;
int dui[430],zan[430],c[430];
int ch[430][430],zh[430][430];
int qu[20480];
bool b[11];


inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
 } 


void dfs1(int sum,int opp,int now,int cg)
 {
  if (now==m+1-k) 
  {
   if ((sum&uoo)!=0) return;
 int og=sum>>(m+1-k); 
 if (qu[og]==0)
  {
   ++cnt; dui[cnt]=og; qu[og]=cnt; ch[cnt][opp]+=1; 
memset(b,true,sizeof(b)); dfs1(og,cnt,0,0); memset(b,false,sizeof(b));return;
  }
 ch[qu[og]][opp]+=1; return;
}
for (int i=cg+1;i<=m+1+m+1-k;++i)
{
int ty=(1<<(i-1));
if ((sum&ty)!=0)
{
 for (int j=1;j<=m+1-k;++j)
  if (b[j] && j+1-i<=0 && i<=j+m+1)
{
  b[j]=false;
    dfs1(sum-ty+(1<<(j+m)),opp,now+1,i);
    b[j]=true;
  }
}
}
 }
 
void work()
 {
    while (sug!=0)
     {
      if (sug%2==1)
      {
      memset(zan,0,sizeof(zan));
      for (int i=1;i<=cnt;++i)
      for (int j=1;j<=cnt;++j)
   {
    zan[i]=(zan[i]+ch[i][j]*c[j])%MOD;

memcpy(c,zan,sizeof(zan));
}
memset(zh,0,sizeof(zh));
for (int i=1;i<=cnt;++i)
 for (int j=1;j<=cnt;++j)
  for (int k=1;k<=cnt;++k)
  {
    zh[i][j]=(zh[i][j]+ch[i][k]*ch[k][j])%MOD;
}
memcpy(ch,zh,sizeof(zh));
sug=sug/2;
}
 }
 
int main()
{
n=read(); k=read(); m=read(); uoo=0; pu=1;
for (int i=1;i<=m+1-k;++i)
{
uoo=uoo+(1<<(i-1));
pu=(pu*i)%MOD;
}
memset(ch,0,sizeof(ch)); memset(c,0,sizeof(c));
cnt=0; int sum=0;
for (int i=1;i<=k;++i)
{
sum=sum+(1<<(i-1));
}
sug=(n-k)/(m-k+1);
sum=sum<<(m-k+1); ++cnt; dui[cnt]=sum; qu[sum]=cnt;
memset(b,true,sizeof(b));
dfs1(sum,1,0,0);
c[1]=1; 
    work();
    ans=0;
    int op=0; int oh=(n-k)%(m-k+1);
    for (int i=1;i<=k-oh;++i)
     op=op+(1<<(i-1));
    op=op<<(m+1-k+oh);
for (int i=1;i<=cnt;++i)
if ((dui[i]&op)==op && (dui[i]%2==0))
{
  int oq=1; int ji=0;
  if (oh!=0) 
for (int j=1;j<=m+1;++j)
    {
    int ty=(1<<(j-1));
    if ((dui[i]&ty)!=0)
     {
      oq=(oq*(min(oh,j-1)-ji))%MOD; ++ji;
 }
    if (ji==oh) break;
}
       ans=(ans+c[i]*oq)%MOD;
}
printf("%d",ans);
}

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m,k,cnt,ans,uoo,sug,pu;
const int MOD=30031;
int dui[430],zan[430],c[430];
int ch[430][430],zh[430][430];
int qu[20480];
bool b[11];


inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
 } 


void dfs1(int sum,int opp,int now,int cg)
 {
  if (now==m+1-k) 
  {
   if ((sum&uoo)!=0) return;
 int og=sum>>(m+1-k); 
 if (qu[og]==0)
  {
   ++cnt; dui[cnt]=og; qu[og]=cnt; ch[cnt][opp]+=1; 
memset(b,true,sizeof(b)); dfs1(og,cnt,0,0); memset(b,false,sizeof(b));return;
  }
 ch[qu[og]][opp]+=1; return;
}
for (int i=cg+1;i<=m+1+m+1-k;++i)
{
int ty=(1<<(i-1));
if ((sum&ty)!=0)
{
 for (int j=1;j<=m+1-k;++j)
  if (b[j] && j+1-i<=0 && i<=j+m+1)
{
  b[j]=false;
    dfs1(sum-ty+(1<<(j+m)),opp,now+1,i);
    b[j]=true;
  }
}
}
 }
 
void work()
 {
    while (sug!=0)
     {
      if (sug%2==1)
      {
      memset(zan,0,sizeof(zan));
      for (int i=1;i<=cnt;++i)
      for (int j=1;j<=cnt;++j)
   {
    zan[i]=(zan[i]+ch[i][j]*c[j])%MOD;

memcpy(c,zan,sizeof(zan));
}
memset(zh,0,sizeof(zh));
for (int i=1;i<=cnt;++i)
 for (int j=1;j<=cnt;++j)
  for (int k=1;k<=cnt;++k)
  {
    zh[i][j]=(zh[i][j]+ch[i][k]*ch[k][j])%MOD;
}
memcpy(ch,zh,sizeof(zh));
sug=sug/2;
}
 }
 
int main()
{
n=read(); k=read(); m=read(); uoo=0; pu=1;
for (int i=1;i<=m+1-k;++i)
{
uoo=uoo+(1<<(i-1));
pu=(pu*i)%MOD;
}
memset(ch,0,sizeof(ch)); memset(c,0,sizeof(c));
cnt=0; int sum=0;
for (int i=1;i<=k;++i)
{
sum=sum+(1<<(i-1));
}
sug=(n-k)/(m-k+1);
sum=sum<<(m-k+1); ++cnt; dui[cnt]=sum; qu[sum]=cnt;
memset(b,true,sizeof(b));
dfs1(sum,1,0,0);
c[1]=1; 
    work();
    ans=0;
    int op=0; int oh=(n-k)%(m-k+1);
    for (int i=1;i<=k-oh;++i)
     op=op+(1<<(i-1));
    op=op<<(m+1-k+oh);
for (int i=1;i<=cnt;++i)
if ((dui[i]&op)==op && (dui[i]%2==0))
{
  int oq=1; int ji=0;
  if (oh!=0) 
for (int j=1;j<=m+1;++j)
    {
    int ty=(1<<(j-1));
    if ((dui[i]&ty)!=0)
     {
      oq=(oq*(min(oh,j-1)-ji))%MOD; ++ji;
 }
    if (ji==oh) break;
}
       ans=(ans+c[i]*oq)%MOD;
}
printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值