【填坑/xdoj难题集】xdoj 2018校赛 现场赛 H敬老师的手环2

这道题应该算是那次校赛时最难的一道题了吧,是唯一一道没人做出来的题目,不过,在经历了这么多题海的洗礼之后,我发现其实这道题并不是那么的难,也是套路。先说说当时的悲惨经历,看到之后认为就是一道简单的状压dp,所以写了一个矩阵快速幂,结果发现对不上答案,仔细一想才发现有无数重复的情况,并且这些重复和手环的最小循环节有关,这样我一下子就不知所措了,我在之前的文章里也写到过可能是有一种比较高明的方法去重,事实证明的确是这样,在学习了反演和polya定理之后,才发现去重其实只是一个模板的问题,这样这道题其实是两部分,首先算出长度为k的不可旋转时候的种类数,也就是一个状压dp,以及使用polya模板去重,由于我保留了之前比赛的时候写的代码(比完赛考代码是一个好习惯),我(之前的那个)也算是不孚众望,把前一个部分写对了,所以前一个部分就直接拷贝了,后一个部分就是贴模板的事,不过当我满心欢喜地以为把这道题秒杀的时候,我才发现一个更坑的问题——超时,这道题只给了1s,我用了一些邪术开大了这道题的时间之后发现我写的长度为8矩阵快速幂要4s,所以我做了两个优化,第一因为底矩阵是恒定的,所以我直接打表打出了每个2的幂次矩阵,这样就少了一大半(因为每次ans不一定乘a)的计算,然而还是超了300ms,之后我手足无措了,只好打表找规律,我打了一个矩阵的次方,发现某些位永远是0,所以我就跳过了一些为的计算,这样总算是可以了。

总结一下,这道题还是可以的,不过现在看来远没有当初想的那么艰难,把两部分想清楚的话其实是挺简单的,看来还是积累的知识不够导致的,经历了这些天的多校赛,我才发现真的是人外有人,天外有天,看来修炼是永远无法停歇的。

贴个代码吧

# include <cstdio>
# include <cstring>
# include <algorithm>

using namespace std;

const int Mod = 1e9 + 7;

typedef long long ll;

const int MAX_N = 1000;

struct mat
{
    ll val[8][8];
};

mat zz[30];

mat t = {
            {
            {0 , 1 , 0 , 0 , 1 , 0 , 0 , 1} , 
            {1 , 0 , 0 , 0 , 0 , 0 , 1 , 0} , 
            {0 , 0 , 0 , 0 , 0 , 1 , 0 , 0} ,
            {0 , 0 , 0 , 0 , 1 , 0 , 0 , 0} , 
            {1 , 0 , 0 , 1 , 0 , 0 , 0 , 0} , 
            {0 , 0 , 1 , 0 , 0 , 0 , 0 , 0} , 
            {0 , 1 , 0 , 0 , 0 , 0 , 0 , 0} , 
            {1 , 0 , 0 , 0 , 0 , 0 , 0 , 0}
    }
};

void mul(mat A , mat B , mat &D)
{
    mat C = {0};
    int i, j, k;

    if(B.val[0][0])
    {
        for(i = 0 ; i < 8 ; i++)
        {
            for(j = i % 3 ; j < 8 ; j += 3)
            {
                for(k = i % 3 ; k < 8 ; k += 3)
                {
                    C.val[i][j] += A.val[i][k] * B.val[k][j];
                    C.val[i][j] %= Mod;
                }
            }
        }

        memcpy(D.val , C.val , sizeof(C.val));
        return;
    }

    for(i = 0 ; i < 8 ; i++)
    {
        for(j = 0 ; j < 8 ; j++)
        {
            for(k = 0 ; k < 8 ; k++)
            {
                C.val[i][j] += A.val[i][k] * B.val[k][j];
                C.val[i][j] %= Mod;
            }
        }
    }

    memcpy(D.val , C.val , sizeof(C.val));
}

mat po(ll n)
{
    mat B = {0};

    int i;
    for(i = 0 ; i < 8 ; i++)
        B.val[i][i] = 1;

    i = 0;
    while(n)
    {
        if(n & 1)
            mul(B , zz[i] , B);

        n >>= 1;
        i++;
    }

    return B;
}

ll sea(int n)
{
    ll ans = 0;

    mat A = po(n);

    int i;
    for(i = 0 ; i < 8 ; i++)
        ans += A.val[i][i];

    return ans % Mod;
}

int N;
int box[MAX_N];
int num;
int st[MAX_N];
int top;

int po(int a , ll b , int mo)
{
    int ans = 1;
    while(b)
    {
        if(b & 1)
            ans = (ll)ans * a % mo;

        b >>= 1;
        a = (ll)a * a % mo;
    }

    return ans;
}

void div(int n)
{
    num = top = 0;
    box[num++] = 1;

    int i, j;
    for(i = 2 ; (ll)i * i <= n ; i++)
    {
        if(n % i == 0)
        {
            int siz = num;
            st[top++] = i;

            while(n % i == 0)
            {
                n /= i;
                for(j = 0 ; j < siz ; j++)
                {
                    box[num] = box[num - siz] * i;
                    num++;
                }
            }
        }
    }

    if(n - 1)
    {
        int siz = num;
        st[top++] = n;
        for(j = 0 ; j < siz ; j++)
        {
            box[num] = box[num - siz] * n;
            num++;
        }
    }
}

void polya()
{
    div(N);

    int i, j;
    ll res = 0;

    for(i = 0 ; i < num ; i++)
    {
        ll euler = box[i];
        for(j = 0 ; j < top ; j++)
        {
            if(box[i] % st[j] == 0)
                euler = euler / st[j] * (st[j] - 1);
        }

        res = (res + euler % Mod * sea(N / box[i])) % Mod;
    }

    printf("%lld\n", res * po(N , Mod - 2 , Mod) % Mod);
}

int main()
{
    int i;
    zz[0] = t;

    int j, k;
    for(i = 1 ; i < 30 ; i++)
    {
        mul(zz[i - 1] , zz[i - 1] , zz[i]);
    }

    while(~scanf("%d", &N))
    {
        polya(); 
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40772738/article/details/81609254