【xdoj难题集】1228 敬老师的手环1

题目链接

也算是一道所谓的毒瘤题了吧,不过其实如果知道polya的话并不是很难,这道题计算不旋转的种类数其实不是很难,但是如何解决旋转的去重就需要技术了,也就是polya,如果不太清楚的可以自行查阅挑战程序设计的高级篇数学部分的最后polya定理,那个模板非常不错(算是挑战里不错能用的了,不过也可以优化,详细见后面的代码),基本上就是直接套用模板就可以了。再说说前面算种类数的问题,2的确是比3简单多了,本来也想写一个矩阵快速幂的,后来发现基本不需要,首先交错的如果出现只能一直交错,所以如果偶数就是2,奇数0,之后就是不交错的情况,我发现这个递推式恰好是斐波那契数列数列,所以直接套用模板即可(当然这里有矩阵快速幂)。

贴代码

# include <cstdio> 
# include <cstring>

const int Mod = 1e9 + 7;
const int MAX_N = 1e4; 

typedef long long ll;

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

namespace juzhen
{   
    typedef int mtype;
    typedef long long ll; 

    const int MAX_N = 2;
    const int Mod = 1e9 + 7;

    int N = MAX_N;
    int M = MAX_N;
    int K = MAX_N;

    void mul(mtype (&A)[MAX_N][MAX_N] , mtype (&B)[MAX_N][MAX_N] , mtype (&C)[MAX_N][MAX_N])
    {
        mtype D[MAX_N][MAX_N] = {0};

        int i, k, j;
        for(i = 0 ; i < N ; i++)
            for(k = 0 ; k < M ; k++)
                for(j = 0 ; j < K ; j++)
                    D[i][j] = (D[i][j] + (ll)A[i][k] * B[k][j]) % Mod;

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

    void pow(mtype (&A)[MAX_N][MAX_N] , mtype (&C)[MAX_N][MAX_N] , ll n)
    {
        mtype B[MAX_N][MAX_N] = {0};

        int i;
        for(i = 0 ; i < N ; i++)
            B[i][i] = 1;

        while(n)
        {
            if(n & 1)
                mul(A , B , B);

            n >>= 1;
            mul(A , A , A);
        }

        memcpy(C , B , sizeof(C));
    }

    mtype fib(int n)
    {
        mtype A[MAX_N][MAX_N];
        A[0][0] = 1;
        A[0][1] = 1;
        A[1][0] = 1;
        A[1][1] = 0;

        pow(A , A , n + 1);
        return A[0][1];
    }
}

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 solve()
{
    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);
        }

        int x = N / box[i];

        ll sum = x % 2 ? 0 : 2;
        //printf("%d\n", x);
        sum += juzhen::fib(x) + juzhen::fib(x - 2);

        res += euler % Mod * sum % Mod;
        res %= Mod;
    }

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

int main()
{
    while(~scanf("%d", &N))
        solve();

    return 0;
}
阅读更多
换一批

没有更多推荐了,返回首页