• [HNOI2010]公交线路


    XXIII.[HNOI2010]公交线路

    状压+矩乘的好题。

    因为每\(p\)个位置中,每辆车就至少有\(1\)个位置,

    所以我们可以状压一下。

    \(f[i][j]\)表示:

    区间\([i,i+p-1]\)内的车站现在的规划情况是\(j\)的方案数。

    显然,必有\(j\)的第\(p\)位是\(1\),且\(j\)共有\(k\)位是\(1\)\(j\)的第\(p\)位对应着\(i\))。

    \(f[i][j]=\sum f[i-1][k]\),其中\(k\)能转移到\(j\)

    那什么样的\(k\)能转移到\(j\)呢?

    我们将\(k\)左移一位(即增加了 \(i+p-1\) 一位),然后删去第\(p\)位的数(即删去第 \(i-1\) 位),得到了一个\(k'\)

    如果\(k'\)\(j\)只相差恰好\(1\),那么\(k\)就可以转移到\(j\)(第\(i-1\)位的车刚好跑到了着相差的一位)。

    然后发现,对于每个\(f[i][j]\),它的祖先的\(k\)都是完全一致的;因此可以矩乘优化,建立转移矩阵\(T[k][j]\),如果状态\(k\)可以转移到\(j\),则\(T[k][j]=1\),否则为\(0\)

    则复杂度为\(S^3\log n\),其中\(S\)是合法状态数量(即符合\(j\)的第\(p\)位是\(1\),且\(j\)共有\(k\)位是\(1\)\(j\)的数量)。我们有\(S=C_{p-1}^{k-1}\),当\(p=10,k=5\ \operatorname{or}\ 6\)时取得最大值,有\(S=C_9^4\ \operatorname{or}\ C_9^5=126\)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int mod=30031;
    int n,m,p,len,sta[150];
    struct mat{
    	int g[150][150];
    	mat(){memset(g,0,sizeof(g));}
    	friend mat operator *(const mat &x,const mat &y){
    		mat z;
    		for(int i=0;i<len;i++)for(int j=0;j<len;j++)for(int k=0;k<len;k++)(z.g[i][j]+=x.g[i][k]*y.g[k][j])%=mod;
    		return z;
    	}
    }X,I;
    bool che(int x,int y){
    	x<<=1,x-=(1<<p);
    	return __builtin_popcount(x^y)<=1;
    }
    void ksm(int y){
    	for(;y;X=X*X,y>>=1)if(y&1)I=I*X;
    }
    int main(){
    	scanf("%d%d%d",&n,&m,&p);
    	for(int i=(1<<(p-1));i<(1<<p);i++)if(__builtin_popcount(i)==m)sta[len++]=i;
    	for(int i=0;i<len;i++)I.g[i][i]=1;
    	for(int i=0;i<len;i++)for(int j=0;j<len;j++)X.g[i][j]=che(sta[i],sta[j]);
    	ksm(n-m);
    	printf("%d\n",I.g[len-1][len-1]);
    	return 0;
    } 
    

  • 相关阅读:
    洛谷 2574 XOR的艺术
    洛谷 1774 最接近神的人
    洛谷 3398 仓鼠找sugar 【模板】判断树上两链有交
    洛谷 2440 木材加工
    洛谷 1824 进击的奶牛
    洛谷 1873 砍树
    洛谷 1577 切绳子
    51nod1485 字母排序
    51nod1055 最长等差数列
    51nod1128 正整数分组V2
  • 原文地址:https://www.cnblogs.com/Troverld/p/14596974.html
Copyright © 2020-2023  润新知