湖南大学第十四届ACM程序设计新生杯(重现赛)L-The Digits String (矩阵快速幂)

题目链接

题目描述

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
2
3
4

输出

3
25
249
479

思路

长度为1有四种情况:

  1. %4 == 0 有3个
  2. %4 == 1 有3个
  3. %4 == 2 有2个
  4. %4 == 3 有2个

计算长度为N的分为四种情况:
令长度为N-1模4为{0, 1, 2, 3}的数量为T0, T1, T3, T4

  1. %4 == 0
    (%4=0) * T0 + (%4=1) * T3 + (%4=2) * T2 + (%4=3) * T1
  2. %4 == 1
    (%4=0) * T1 + (%4=1) * T0 + (%4=2) * T3 + (%4=3) * T2
  3. %4 == 2
  4. (%4=0) * T2 + (%4=1) * T1 + (%4=2) * T0 + (%4=3) * T3
  5. %4 == 3
    (%4=0) * T3 + (%4=1) * T2 + (%4=2) * T1 + (%4=3) * T0

根据这个思路可以用矩阵快速幂加快一下

#include <bits/stdc++.h>
#define LL  long long
#define P pair<int, int>
#define lowbit(x) (x & -x)
#define mem(a, b) memset(a, b, sizeof(a))
#define REP(i, n) for (int i = 1; i <= (n); ++i)
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define N 100005
using namespace std;

void mul(LL x[], LL y[]) {
    LL t[4];
    t[0] = x[0] * y[0] + x[1] * y[3] + x[3] * y[1] + x[2] * y[2];
    t[1] = x[1] * y[0] + x[0] * y[1] + x[2] * y[3] + x[3] * y[2];
    t[2] = x[0] * y[2] + x[2] * y[0] + x[1] * y[1] + x[3] * y[3];
    t[3] = x[0] * y[3] + x[3] * y[0] + x[1] * y[2] + x[2] * y[1];
    rep (i, 4)  x[i] = t[i] % 2019;
}

LL quick(LL x) {
    LL b[4] = {3, 3, 2, 2};
    LL a[4] = {3, 3, 2, 2};
    while (x) {
        if (x & 1) mul(a, b);
        mul(b, b);
        x >>= 1;
    }
    return a[0];
}

int main() {
#ifndef ONLINE_JUDGE
   freopen("in.txt", "r", stdin);
   // freopen("out.txt", "w", stdout);
#endif
    LL n;
    while (scanf("%lld", &n) != EOF) {
        LL ans = quick(n-1);
        printf("%d\n", ans % 2019);
    }
    return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值