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);
}
發佈了149 篇原創文章 · 獲贊 2 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章