L The Digits String(没有写完,有空补)

链接:https://ac.nowcoder.com/acm/contest/338/L
来源:牛客网

  Consider digits strings with length n, how many different strings have the sum of digits are multiple of 4?

输入描述:

There are several test cases end with EOF. For each test case, there is an integer in one line: n, the length of the digits string. (1≤n≤1,000,000,000).

输出描述:

For each case, output the number of digits strings with length n have the sum of digits are  multiple of 4 in one line. The numbers maybe very large, you should output the result modular 2019.
示例1

输入

复制
1
2
3
4

输出

复制
3
25
249
479

题目大意
• 求长度为n的数字串中,有多少个这样数字串,其数字
之和是4的倍数(包括0)
• 输入:每组测试数据一行,包含一个正整数n(1 ≤ c≤ 109)
• 输出:对于每组测试数据,输出一行,包含一个整数, 表示有多少个这样数字串,其数字之和是4的倍数(包 括0)。因为这个结果很大,所以将值模2019输出

• 本题快速幂,复杂度为O(logn)。标程在1000组测试 数据下的运行时间约为60毫秒(第二标程运行时间约 30毫秒)。建议时间限制为1秒,空间限制为64M。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cfloat>
#include <climits>
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <bitset>
using namespace std;

#define LL long long
const int matrix_size = 4;
const int MOD = 2019;

int add(int a, int b)
{
    a += b;
    if(a >= MOD)
    {
        return a - MOD;
    }
    return a;
}

struct Matrix
{
    int size;
    int num[matrix_size][matrix_size];

    void operator=(const Matrix &m)
    {
        for(int i = 0; i < size; ++i)
        {
            memcpy(num[i], m.num[i], sizeof(int) * size);
        }
    }

    void Init()
    {
        for(int i = 0; i < size; ++i)
        {
            memset(num[i], 0, sizeof(int) * size);
            num[i][i] = 1;
        }
    }

    void Set()
    {
        size = 4;
        memset(num, 0, sizeof(num));
        for(int j = 0; j < 4; ++j)
        {
            for(int i = 0; i < 10; ++i)
            {
                ++num[(j + i) % 4][j];
            }
        }
    }

    void operator*=(const Matrix &m)
    {
        static Matrix ans;
        ans.size = size;
        for(int i = 0; i < size; ++i)
        {
            for(int j = 0; j < size; ++j)
            {
                ans.num[i][j] = 0;
                for(int k = 0; k < size; ++k)
                {
                    ans.num[i][j] = add(ans.num[i][j], (LL)num[i][k] * m.num[k][j] % MOD);
                }
            }
        }
        (*this) = ans;
    }

    void fast_pow(LL n)
    {
        static Matrix ans;
        ans.size = size;
        for(ans.Init(); n != 0; n >>= 1)
        {
            if((n & 1) == 1)
            {
                ans *= (*this);
            }
            (*this) *= (*this);
        }
        (*this) = ans;
    }
};

int n;
Matrix m;

int main()
{
#ifdef Dmaxiya
    freopen("test.txt", "r", stdin);
#endif // Dmaxiya
    ios::sync_with_stdio(false);

    while(scanf("%d", &n) != EOF)
    {
        m.Set();
        m.fast_pow(n);
        printf("%d\n", m.num[0][0]);
    }

    return 0;
}
View Code

 标答

•#include <stdio.h>#define M 2019#define L 4#define LP(i) for(i=0;i<L;++i)void Product(int x[L][L],int y[L][L],int z[L][L]){

•    int i,j,k,w[L][L]={0};

•    LP(i)LP(j)LP(k)w[i][j]=(w[i][j]+x[i][k]*y[k][j])%M;

•    LP(i)LP(j)z[i][j]=w[i][j];}

•

•void FPow(int n,int r[L][L]){

•    int i,j,A[L][L]={{3,2,2,3},{3,3,2,2},{2,3,3,2},{2,2,3,3}};

•    LP(i)LP(j)r[i][j]=i==j?1:0;

•while(n){

•if(n&1)Product(r,A,r);

•Product(A,A,A);

•    n>>=1;}}


•int cal(int n){

•int r[L][L];

•FPow(n,r);

•    return    (3*r[0][0]+3*r[0][1]+2*r[0][2]+2*r[0][3])%M;}

•

•int main(){

•int n;

•while(scanf("%d",&n)!=EOF&&n>0)

•printf("%d\n",cal(n-1));

•return 0;}
View Code
解题思路(续)
• 矩阵
• 3 2 2 33 3 2 22 3 3 22 2 3 3
• 有四个特征根,分别是0,101+i,1-i;
• 所以an=x10n+ycos(nπ/4)+zsin(nπ/4),根据
a1=3,a2=25,a3=249,可得:
• an=(10n+2sqrt(2)ncos(nπ/4))/4;
• 同样快速幂求得答案。
•#include <stdio.h>#define M 2019int rt[2][32],et[8]={2,2,0,-4,-8,-8,0,16};
•int FPow(int f,int n){
•    int r=1,m=0;
•while(n){
•    if(n&1)r=(r*rt[f][m])%M;
•    m++;
•    n>>=1;}
•return r;}
•
•int cal(int n){
•int r1,r2;
•    r1=FPow(0,n);
•    r2=((FPow(1,n/8)*et[n%8])%M+M)%M;
•    return ((r1+r2)*505)%M;
•    }
•int main(){
•int n,i;
•    rt[0][0]=10;rt[1][0]=16;
•    for(i=1;i<32;++i){
•    rt[0][i]=(rt[0][i-1]*rt[0][i-1])%M;
•    rt[1][i]=(rt[1][i-1]*rt[1][i-1])%M;}
•while(scanf("%d",&n)!=EOF&&n>0)
•printf("%d\n",cal(n));
•return 0;}
View Code

 

STZG的代码

 

posted @ 2019-01-06 19:36  DWVictor  阅读(391)  评论(0编辑  收藏  举报