【u026】花园(garden)

【问题描述】
小L有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为1~N(2<=N<=1015)。他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻M(2<=M<=5,M<=N)个花圃中有不超过K(1<=K< M)个C形的花圃,其余花圃均为P形的花圃。
例如,N=10,M=5,K=3。则
CCPCPPPPCC 是一种不符合规则的花圃;
CCPPPPCPCP 是一种符合规则的花圃。
请帮小L求出符合规则的花园种数Mod 1000000007
由于请您编写一个程序解决此题。

【输入文件】
一行,三个数N,M,K。
【输出文件】
花园种数Mod 1000000007

【样例输入1】
10 5 3
【样例输出1】
458

【样例输入2】
6 2 1
【样例输出2】
18

【数据规模】
40%的数据中,N<=20;
60%的数据中,M=2;
80%的数据中,N<=105。

【题目链接】:http://noi.qz5z.com/viewtask.asp?id=u029

【题解】

先处理处1..m的情况,对于每个位置都有两个选择;
和0..(2^m)-1的二进制一一对应;
1的个数和1的个数对应;
处理出1的个数小于等于k的状态;
表示这些状态是可行的;
然后考虑整体往右移动一位;
然后获取了新的状态;

[l..r]
->[l+1..r+1]
这里枚举l..r的状态,然后对于新获取的状态;
只有两种情况;
r+1为0或者是r+1为1;
如果新获取的状态1的个数小于等于k;
则表示从l..r可以到达l+1..r+1;
这个可以用位运算搞出来;
(这个位运算自己推吧,看别人的程序挺可怕的..)
然后就能获取出一个二维的矩阵了;
求这个矩阵的(N-M)次幂;
然后枚举初始的M个位置的状态,和末尾的M个位置的状态;
看看练成环之后符不符合要求;
符合要求的话就递增答案.
这里矩阵乘法我写成函数的形式RE了。。。
所以就没写成函数啦

【完整代码】

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <iostream>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%lld",&x)
#define ref(x) scanf("%lf",&x)

typedef pair<int,int> pii;
typedef pair<LL,LL> pll;

const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
const double pi = acos(-1.0);
const int N = 110;
const int INF = 0x3f3f3f3f;
const LL mod = 1000000007;

struct juzhen
{
    LL a[64][64];
    void init()
    {
        rep1(i,0,63)
            rep1(j,0,63)
                a[i][j] = 0;
    }
};

int ma,num;
LL ans = 0,n,rr[100],m,k;
juzhen t,a;
bool bo[64+10];

void in()
{
    cin >> n >> m >> k;
}

void pre()
{
    ma = (1<<m)-1;
    rep1(i,0,ma)
    {
        int j = i,cnt = 0;
        while (j)
        {
            cnt+=(j&1);
            j>>=1;
        }
        if (cnt>k)
            bo[i] = false;
        else
            bo[i] = true;
    }
    t.init();
    rep1(i,0,ma)
    if (bo[i])
    {
        int te = ma-(1<<(m-1));
        te = i&te;
        te<<=1;
        t.a[i][te] = 1;
        if (bo[te+1])
            t.a[i][te+1] = 1;
    }
}

void special()
{
    if (n==m)
    {
        int temp = 0;
        rep1(i,0,ma)
        if (bo[i])
            temp++;
        printf("%d
",temp);
        exit(0);
    }
}

void get_ksm()
{
    LL tt = n-m;
    a.init();
    rep1(i,0,ma)
        rep1(j,0,ma)
            a.a[i][j] = t.a[i][j];
    while (tt)
    {
        if (tt==1) break;
        num++;
        rr[num] = tt&1;
        tt>>=1;
    }
   // exit(0);
    rep2(i,num,1)
    {
        //a = cheng(a,a);
        juzhen c;
        c.init();
        rep1(i,0,ma)
            rep1(j,0,ma)
                rep1(k,0,ma)
                    c.a[i][j] = (c.a[i][j] + a.a[i][k]*a.a[k][j])%mod;
        rep1(i,0,ma)
            rep1(j,0,ma)
                a.a[i][j] = c.a[i][j];

        if (rr[i]==1)
        {
            //a = cheng(a,t);
            juzhen c;
            c.init();
            rep1(i,0,ma)
                rep1(j,0,ma)
                    rep1(k,0,ma)
                        c.a[i][j] = (c.a[i][j] + a.a[i][k]*t.a[k][j])%mod;
            rep1(i,0,ma)
                rep1(j,0,ma)
                    a.a[i][j] = c.a[i][j];
        }
    }
}

void get_ans()
{
    juzhen b;
    rep1(i,0,ma)
        if (bo[i])
        {
            b.init();
            b.a[0][i] = 1;
            //b = cheng(b,a);

            juzhen c;
            c.init();
            rep1(i,0,ma)
                rep1(j,0,ma)
                    rep1(k,0,ma)
                        c.a[i][j] = (c.a[i][j] + b.a[i][k]*a.a[k][j])%mod;
            rep1(i,0,ma)
                rep1(j,0,ma)
                    b.a[i][j] = c.a[i][j];

            rep1(j,0,ma)
            if (bo[j])
            {
                bool ok = true;
                LL t = j<<m;
                t = t|i;
                rep1(k,1,m-1)
                {
                    int d = (1<<m)-1;
                    d = d<<(m-k);
                    d = d&t;
                    d>>=(m-k);
                    if (!bo[d])
                    {
                        ok = false;
                        break;
                    }
                }
                if (ok)
                    ans = (ans+b.a[0][j])%mod;
            }
        }
}

void o()
{
    cout << ans << endl;
}

int main()
{
    //freopen("D:\rush.txt","r",stdin);
    in();
    pre();
    special();
    get_ksm();
    get_ans();
    o();
    //printf("
%.2lf sec 
", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

原文地址:https://www.cnblogs.com/AWCXV/p/7626521.html