CF756F 题解

CF756F

原本以为校内有神仙要讲评这题,就赶快去做了。结果啊,是我题号记错的 … \dots

题目大意:

给出一个字符串请解析这个字符串构成的数。

  • l − r l - r lr 表示 l ∼ r l \sim r lr 中的所有数, 8 − 10 8 -10 810 表示 8910 8910 8910
  • + x + x +x 表示单纯增加一个 x x x,如 8 − 10 + 5 8-10+5 810+5 表示 89105 89105 89105

我们称上面的这样的形式为表达式。

  • 对于 a ( 表达式 ) a(\text{表达式}) a(表达式) 这样的形式,表示写 a a a 遍表达式表示的数。
  • 运算优先级是 ( ) , + , − (), +, - (),+, 从高到低。

考虑建立一个表达式树,进行分治处理。

感觉这里最妙的一点就是节点的合并。

因为我们节点的合并可能是重复写很多次,我们不妨记录节点的数值和长度作为一点类。设其为 ( x , y ) (x, y) (x,y)

我们分类讨论一下合并的情况:

  • a + b a + b a+b ( a x × 1 0 b y + b x , a y + b y ) (a_x \times 10^{b_y} + b_x, a_y + b_y) (ax×10by+bx,ay+by)
  • a ( b ) a(b) a(b) ( b x × ( ( 1 0 b y ) a x − 1 ) ÷ ( 1 0 b y − 1 ) , b y × a x ) (b_x \times ({(10^{b_y})}^{a_x} - 1) \div (10^{b_y} - 1), b_y \times a_x) (bx×((10by)ax1)÷(10by1),by×ax)。这里代码里有注释更清晰。
  • a − b a-b ab 我们分类讨论,对于每一种长度分别进行合并。不妨设 a , b a, b a,b 长度相同为 n n n。那么我们就要计算 ∑ i = 0 a − b ( b − i ) × ( 1 0 n ) i \sum_{i = 0} ^ {a - b} (b - i) \times (10^n)^i i=0ab(bi)×(10n)i。这个显然是一个等差等比数列。

设这个数列是 S S S S i = ( ( − 1 ) × i + b ) × 1 0 n i S_i = ((-1) \times i + b) \times 10^{ni} Si=((1)×i+b)×10ni

那么 a = − i , b = b , q = 1 0 n a = -i, b = b,q = 10^n a=i,b=b,q=10n

得到 x = − i 1 0 n − 1 , y = b + i 1 0 n − 1 1 0 n − 1 x = \frac{-i}{10^n - 1}, y = \frac{b + \frac{i}{10^n - 1}}{10^n - 1} x=10n1i,y=10n1b+10n1i

那么这个数列的前 w w w 项的和就是 1 0 n ( x + 1 ) × ( x w + y ) − y 10^{n(x + 1)} \times (xw + y) - y 10n(x+1)×(xw+y)y


那么说人话就是如下的柿子:
( b + 1 ) × 1 0 n × ( b − a + 1 ) − 1 1 0 n − 1 − ( b − a + 1 ) 1 0 n × ( b − a + 2 ) − ( b − a + 2 ) 1 0 n × ( b − a + 1 ) + 1 ( 1 0 n − 1 ) 2 (b + 1) \times \frac{10^{n \times (b - a + 1)} - 1}{10^n - 1} - \frac{(b - a + 1) 10^{n \times(b -a + 2)} - (b - a + 2) 10^{n\times(b - a + 1)} + 1}{(10^n - 1) ^ 2} (b+1)×10n110n×(ba+1)1(10n1)2(ba+1)10n×(ba+2)(ba+2)10n×(ba+1)+1
由此可以发现我们的 a , b a, b a,b 可能会出现在指数上,取模是不同的,所以我们需要对于每一个数额外存储其取模 φ ( m o d ) \varphi(mod) φ(mod) 的值。

#include <bits/stdc++.h>
using namespace std;

const int mod = 1e9 + 7;

template <typename T,typename... Args> inline void r1(T& t, Args&... args) {
    r1(t);  r1(args...);
}

typedef long long ll;
//#define int long long
const int maxn = 1e5 + 5;
const int N = 1e5;
const int maxm = maxn << 1;

int nxt[maxn], pwd[maxn], pwu[maxn];
char s[maxn];
int n;
stack <int> st;

int ksm(int x,int mi,int mod) {
    int res(1);
    while(mi) {
        if(mi & 1) res = 1ll * res * x % mod;
        mi >>= 1;
        x = 1ll * x * x % mod;
    }
    return res;
}

struct Node {
    int x, y;
    Node(int a = 0,int b = 0) : x(a), y(b) {}
    Node operator + (const Node &z) const {
        return Node( ((ll)x * ksm(10, z.y, mod) + z.x) % mod, (y + z.y) % (mod - 1) );
    }
};

int inv(int a) {
    return a <= 1 ? a : (mod - 1ll * mod / a * inv(mod % a) % mod);
}

Node Mul(int a,int b,int ca,int cb,int ln) { // not mi, mi, len
//    printf("A = %d\n", pwd[ln] - 1);
    int A = pwd[ln], iv = inv(A - 1);
    int d = ksm(A, (cb - ca + mod) % (mod - 1), mod);
    int nx, ny;
    nx = 1ll * (b + 1) * (d - 1 + mod) % mod * iv % mod;
    nx = ( nx - 1ll * iv * iv % mod * (b - a + 1 + mod) % mod * d % mod * A % mod + mod ) % mod;
    nx = ( nx + 1ll * iv * iv % mod * (b - a + 2 + mod) % mod * d % mod ) % mod;
    nx = ( nx - 1ll * iv * iv % mod + mod) % mod;
    ny = 1ll * ln * (cb - ca + mod) % (mod - 1);
    return Node(nx, ny);
}

Node Solve(int L,int R) {
    assert(L < R);
    for(int i = L; i < R; ++ i) {
        if(s[i] == '(') { i = nxt[i]; continue; }
        if(s[i] == '+') return Solve(L, i) + Solve(i + 1, R);
    }
    if(s[R - 1] == ')') {
        int mi(0), fmi(0);
        for(int i = L; i < R; ++ i) {
            if(s[i] == '(') {
                Node A = Solve(i + 1, R - 1);
                int d = ksm(10, A.y, mod);
                int ansx, ansy;
                if(d == 1) ansx = 1ll * fmi * A.x % mod;
                else {
                    ansx = 1ll * A.x * (ksm(d, mi, mod) - 1) % mod * inv(d - 1) % mod;
                    /*
                    * 999999999999
                    / 9999
                    = 100010001000
                    */
                    ansx = (ansx + mod) % mod;
                }
                ansy = 1ll * mi * A.y % (mod - 1);
                return Node(ansx, ansy);
            }
            mi = (10ll * mi + s[i] - '0') % (mod - 1);
            fmi = (10ll * fmi + s[i] - '0') % mod;
        }
    }
    int ami(0), afmi(0);
    for(int i = L; i < R; ++ i) {
        if(s[i] == '-') {
            int bmi(0), bfmi(0);
            int la(i - L), lb(R - 1 - i);
            for(++ i; i < R; ++ i) {
                bmi = (10ll * bmi + s[i] - '0') % (mod - 1);
                bfmi = (10ll * bfmi + s[i] - '0') % mod;
            }
            if(la == lb) return Mul(afmi, bfmi, ami, bmi, la);
//            puts("ZZZz");
            Node A;
            A = Mul( afmi, (pwd[la] - 1 + mod) % mod, ami, (pwu[la] - 2 + mod) % (mod - 1), la);
//            puts("CCC");
            for(i = la + 1; i < lb; ++ i) A = A + Mul(pwd[i - 1], (pwd[i] - 1 + mod) % mod, pwu[i - 1], (pwu[i] - 2 + mod) % (mod - 1), i);
//            puts("ZZZ");
//            printf("lb = %d\n", lb);
            A = A + Mul(pwd[lb - 1], bfmi, pwu[lb - 1], bmi, lb);
//            puts("ZZZ");
            return A;
        }
        ami = (10ll * ami + s[i] - '0') % (mod - 1);
        afmi = (10ll * afmi + s[i] - '0')  % mod;
    }
    return Node(afmi, R - L);
}

signed main() {
//    freopen("S.in", "r", stdin);
//    freopen("S.out", "w", stdout);
    int i;
    scanf("%s", s);
    n = strlen(s);
    for(i = 0; i < n; ++ i) {
        if(s[i] == '(') st.push(i);
        if(s[i] == ')') {
            nxt[st.top()] = i;
            st.pop();
        }
    }
    pwu[0] = pwd[0] = 1;
    for(i = 1; i <= N; ++ i) pwd[i] = pwd[i - 1] * 10ll % mod;
    for(i = 1; i <= N; ++ i) pwu[i] = pwu[i - 1] * 10ll % (mod - 1);
    printf("%d\n", Solve(0, n).x);
 	return 0;
}

A c l i n k Aclink Aclink

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值