Logo Wy Online Judge

WyOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#470#92. 「NOIP2020」微信步数Pigsyy100334ms10220kbC++237.0kb2025-04-24 20:47:512025-04-24 20:47:53

answer

#include <bits/stdc++.h>
using namespace std;
bool Mbegin;
void File_Work() {
    freopen("walk.in", "r", stdin);
    freopen("walk.out", "w", stdout);
}
namespace Fast_In_Out {
char buf[1 << 21], *P1 = buf, *P2 = buf;
#define gc (P1==P2&&(P2=(P1=buf)+fread(buf,1,1<<21,stdin),P1==P2)?EOF:*P1++)
int read() {
    int f = 1, x = 0;
    char c = gc;

    while (c < '0' || c > '9') {
        if (c == '-')
            f = -1;

        c = gc;
    }

    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = gc;
    }

    return f * x;
}
void write(int x) {
    if (x < 0)
        x = -x, putchar('-');

    if (x > 9)
        write(x / 10);

    putchar(x % 10 + '0');
}
#undef gc
}
using namespace Fast_In_Out;
/*
注意到走出场地的时刻,就是某一维的坐标范围第一次超出对应的限制范围的时刻。
所以只需要关心每一维坐标的最大值、最小值。
考虑将起点分成两类:走不超过n步就能出去的、走超过n步才能出去的。

对于第一类起点,枚举i表示走i步恰好走出去,
方案数为前i-1步对应的坐标范围在限制范围内的方案数,
减去前i步对应的坐标范围在限制范围内的方案数。
对于两者,合法的起点都在一个高维矩形里,可以乘法计算方案数。

对于第二类起点,考虑将答案拆成最后一轮走的步数和之前走的步数之和(是n的倍数)。

先考虑前者。
枚举一个“假起点”,满足真正的起点走整数轮之后到达“假起点”,
再走n+i步走出场地(1小于等于i小于等于n)。
记一轮之后第i维坐标的增量维dt[i],方便起见,dt[i]≥0且不全为0。
设真起点维(a[1],a[2],…,a[m]),假起点为(b[1],b[2],…,b[m])。
则a[i]=b[i]-y*dt[i](y≥0)。
考虑先固定假起点,则真起点还要满足形如a[i]≥l[i]的若干条限制。
所以真起点的个数为floor(min((b[i]-l[i])/dt[i]))+1。
考虑假起点的坐标范围也是一个高维矩形,可以二维差分算贡献。
同时,假起点的坐标范围满足形如l[i]≤b[i]<r[i]的限制。
设p[i]=r[i]-l[i],方案数为:
Σ(l[1]≤i[1]≤r[1]-1)…Σ(l[m]≤i[m]≤r[m]-1)(floor(min((b[i]-l[i])/dt[i]))+1)
=Σ(0≤j[1]≤p[1]-1)…Σ(0≤j[m]≤p[m]-1)(floor(min(j[i]/dt[i]))+1)
=Σ(q≥0)Σ(0≤j[1]≤p[1]-1)…Σ(0≤j[m]≤p[m]-1)[floor(min(j[i]/dt[i]))≥q]
=Σ(q≥0)∏(1≤i≤m)(max(0,p[i]-q*dt[i]))
注意到q大于等于一个数lim时后面的乘积就会是0,所以可以去掉max。
将式子看作关于q的多项式,方案数为:
Σ(0≤q≤lim-1)∏(1≤i≤m)(p[i]-q*dt[i])
=Σ(0≤q≤lim-1)Σ(0≤i≤m)(f[i]*(q^i))
=(Σ(0≤q≤lim-1)f[i])*(Σ(0≤i≤m)(q^i))
前面的系数容易计算,后面的自然数幂和可以O(m^2)计算。

考虑后者。
枚举y表示走y整轮还没走出边界,然后给答案加上(n×合法起点数)。
发现合法的起点还是高维矩形,且y每增加1,高维矩形第i维的长度就会少dt[i]。
因此前者和后者本质相同。
需要预处理逆元和第二类斯特林数,总复杂度O(nm^2)。
*/
const int N = 5e5 + 8, M = 18, mod = 1e9 + 7;
int n, m, w[M], c[N], d[N], dt[N];
int inv[M + 1], S[M + 1][M + 1]/*第二类斯特林数*/;
void prepare() {
    S[0][0] = 1;

    for (int i = 1; i <= M; i++)
        for (int j = 1; j <= i; j++)
            S[i][j] = (+S[i - 1][j - 1] + 1ll * j * S[i - 1][j] % mod) % mod;

    inv[0] = inv[1] = 1;

    for (int i = 2; i <= M; i++)
        inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
}
struct Space {
    int l[M], r[M], dtx[M];
    Space() {
        memset(l, 0, sizeof(l));
        memset(r, 0, sizeof(r));
        memset(dtx, 0, sizeof(dtx));
    }
    int walk(int c, int d) {
        dtx[c] += d;

        if (dtx[c] < l[c] || dtx[c] > r[c]) {
            l[c] = min(l[c], dtx[c]);
            r[c] = max(r[c], dtx[c]);
            return d;
        }

        return 0;
    }
} spc/*描述各维的坐标区间和位移*/, spc0/*一开始的spc*/;
int calc(int idx, int lim) {
    int tmp = 1, res = 0;

    for (int i = 0; i <= idx; i++) {
        tmp = 1ll * tmp * max(0, lim - i) % mod;
        res = (res + 1ll * tmp * S[idx][i] % mod * inv[i + 1] % mod) % mod;
    }

    return res;
}
int work(int *arr) {
    int lim = mod;

    for (int i = 0; i < m; i++)
        if (dt[i] != 0)
            lim = min(lim, (arr[i] + dt[i] - 1) / dt[i]);

    int f[M] = {0};
    f[0] = 1;

    for (int i = 0; i < m; i++) {
        for (int j = i; j >= 0; j--) {
            f[j + 1] = (f[j + 1] + 1ll * (mod - dt[i]) * f[j] % mod) % mod;
            f[j] = 1ll * arr[i] * f[j] % mod;
        }
    }

    int res = 0;

    for (int i = 0; i <= m; i++)
        res = (res + 1ll * f[i] * calc(i, lim) % mod) % mod;

    return res;
}
bool Mend;
int main() {
    prepare();
    n = read(), m = read();

    for (int i = 0; i < m; i++)
        w[i] = read();

    int ans = 0;

    for (int i = 1; i <= n; i++) {
        c[i] = read() - 1, d[i] = read();

        if (spc.walk(c[i], d[i]) != 0 && spc.r[c[i]] - spc.l[c[i]] <= w[c[i]]) {
            int tmp = 1;

            for (int j = 0; j < m; j++)
                if (j != c[i])
                    tmp = 1ll * tmp * max(0, w[j] - (spc.r[j] - spc.l[j])) % mod;

            ans = (+ans + 1ll * i * tmp % mod) % mod;
        }
    }

    for (int i = 1; i <= n; i++)
        if (spc.dtx[c[i]] < 0)
            d[i] = -d[i];

    for (int i = 0; i < m; i++) {
        if (spc.dtx[i] < 0) {
            spc.dtx[i] = -spc.dtx[i];
            spc.l[i] = -spc.l[i];
            spc.r[i] = -spc.r[i];
            swap(spc.l[i], spc.r[i]);
        }
    }

    spc0 = spc;
    bool flag = 1;

    for (int i = 0; i < m; i++) {
        dt[i] = spc.dtx[i];
        flag &= dt[i] == 0;
    }

    if (flag == 1) {
        bool ok = 0;

        for (int i = 0; i < m; i++)
            ok |= (spc.r[i] - spc.l[i] >= w[i]);

        if (ok == 0)
            printf("-1");
        else
            write(ans);

        return 0;
    }

    int arr[M] = {0};

    for (int i = 1; i <= n; i++) {
        if (spc.walk(c[i], d[i]) != 0 && spc.r[c[i]] - spc.l[c[i]] <= w[c[i]]) {
            bool ok = 1;

            for (int j = 0; j < m; j++)
                if (j != c[i])
                    ok &= (w[j] - (spc.r[j] - spc.l[j]) > 0);

            if (ok == 0)
                continue;

            for (int j = 0; j < m; j++)
                if (j != c[i])
                    arr[j] = w[j] - (spc.r[j] - spc.l[j]);

            arr[c[i]] = w[c[i]] - (spc.r[c[i]] - spc.l[c[i]] - 1);
            ans = (ans + 1ll * i * work(arr) % mod) % mod;
            arr[c[i]] = w[c[i]] - (spc.r[c[i]] - spc.l[c[i]]);
            ans = (ans + 1ll * (mod - i) * work(arr) % mod) % mod;
        }
    }

    for (int i = 0; i < m; i++)
        arr[i] = max(0, w[i] - (spc0.r[i] - spc0.l[i]));

    ans = (ans + 1ll * n * work(arr) % mod) % mod;
    write(ans);
    return 0;
}

Details

小提示:点击横条可展开更详细的信息

Test #1:

score: 5
Accepted
time: 2ms
memory: 9380kb

input:

5 5
2 2 1 3 3
1 1
2 -1
1 1
5 -1
5 1

output:

63

result:

ok "63"

Test #2:

score: 5
Accepted
time: 3ms
memory: 9432kb

input:

5 5
2 2 2 3 2
5 -1
5 1
2 1
2 1
5 1

output:

108

result:

ok "108"

Test #3:

score: 5
Accepted
time: 0ms
memory: 9440kb

input:

5 5
3 3 1 3 2
4 1
4 -1
1 -1
3 -1
2 1

output:

150

result:

ok "150"

Test #4:

score: 5
Accepted
time: 0ms
memory: 9680kb

input:

100 3
8 7 6
1 1
1 -1
3 1
3 -1
3 1
3 -1
3 1
3 -1
1 1
1 -1
1 1
1 -1
2 1
2 -1
1 1
1 -1
2 1
2 -1
3 1
3 -...

output:

-1

result:

ok "-1"

Test #5:

score: 5
Accepted
time: 1ms
memory: 9496kb

input:

100 3
6 7 5
1 1
2 1
3 1
2 -1
2 -1
3 -1
3 -1
2 -1
3 1
2 -1
2 -1
2 1
1 -1
1 1
2 -1
2 -1
2 1
3 -1
3 -1
...

output:

1445

result:

ok "1445"

Test #6:

score: 5
Accepted
time: 0ms
memory: 7396kb

input:

100 3
5 7 6
3 1
1 1
2 -1
2 -1
2 1
2 1
1 1
1 -1
2 1
2 -1
3 1
2 1
3 -1
2 -1
1 1
1 -1
1 -1
3 1
2 1
1 1
...

output:

1823

result:

ok "1823"

Test #7:

score: 5
Accepted
time: 7ms
memory: 7648kb

input:

100000 1
84020
1 -1
1 -1
1 1
1 -1
1 1
1 1
1 -1
1 -1
1 1
1 -1
1 -1
1 1
1 1
1 -1
1 1
1 -1
1 1
1 1
1 1
...

output:

333173136

result:

ok "333173136"

Test #8:

score: 5
Accepted
time: 8ms
memory: 9416kb

input:

100000 1
74078
1 -1
1 1
1 1
1 -1
1 -1
1 -1
1 1
1 1
1 1
1 1
1 1
1 -1
1 1
1 1
1 -1
1 -1
1 -1
1 -1
1 1
...

output:

453472675

result:

ok "453472675"

Test #9:

score: 5
Accepted
time: 5ms
memory: 9388kb

input:

100000 2
788727 548098
1 -1
2 1
2 -1
2 1
1 -1
1 1
2 -1
2 -1
1 -1
2 1
2 -1
2 1
2 -1
1 -1
2 -1
2 1
1 -...

output:

433871022

result:

ok "433871022"

Test #10:

score: 5
Accepted
time: 12ms
memory: 9572kb

input:

100000 2
851838 526074
1 1
1 1
1 1
1 -1
2 -1
2 -1
1 1
2 1
2 1
2 1
2 1
1 1
1 -1
2 1
1 1
2 1
1 -1
2 -1...

output:

635878930

result:

ok "635878930"

Test #11:

score: 5
Accepted
time: 7ms
memory: 9436kb

input:

100000 2
936902 869936
1 -1
1 -1
1 -1
2 -1
2 1
1 -1
2 1
2 1
2 -1
1 1
2 -1
2 -1
1 -1
2 -1
1 -1
1 -1
1...

output:

442317474

result:

ok "442317474"

Test #12:

score: 5
Accepted
time: 5ms
memory: 9416kb

input:

100000 2
696105 696736
2 1
1 -1
1 -1
1 1
1 1
1 -1
1 -1
2 1
2 -1
2 -1
1 -1
1 1
1 -1
2 1
2 -1
1 1
2 -1...

output:

564885404

result:

ok "564885404"

Test #13:

score: 5
Accepted
time: 14ms
memory: 9996kb

input:

500000 10
755576 503368 607237 931815 889701 742191 594456 676526 704905 569952
9 1
9 -1
8 1
8 -1
4 ...

output:

-1

result:

ok "-1"

Test #14:

score: 5
Accepted
time: 39ms
memory: 9744kb

input:

500000 10
843479 559917 806296 766435 965493 781368 889933 632099 689781 934269
3 1
10 1
3 1
3 -1
6 ...

output:

212475448

result:

ok "212475448"

Test #15:

score: 5
Accepted
time: 47ms
memory: 9560kb

input:

500000 10
564550 662731 907937 653446 887637 552698 501487 502890 574491 689451
8 -1
2 1
2 -1
10 -1
...

output:

27023740

result:

ok "27023740"

Test #16:

score: 5
Accepted
time: 52ms
memory: 9200kb

input:

500000 10
918488 957499 964399 900665 976079 674192 501308 980114 958902 545155
6 1
1 -1
1 1
9 1
1 1...

output:

128050940

result:

ok "128050940"

Test #17:

score: 5
Accepted
time: 31ms
memory: 10220kb

input:

500000 3
826619243 796070724 841056572
3 1
2 1
3 -1
1 -1
2 1
2 -1
1 -1
1 1
1 -1
3 1
1 -1
2 -1
3 -1
3...

output:

953829771

result:

ok "953829771"

Test #18:

score: 5
Accepted
time: 34ms
memory: 9324kb

input:

500000 3
956491428 866109891 631435277
2 1
1 -1
1 -1
3 -1
3 1
2 -1
2 1
1 -1
2 1
2 -1
1 -1
2 1
2 1
2 ...

output:

286394049

result:

ok "286394049"

Test #19:

score: 5
Accepted
time: 31ms
memory: 9952kb

input:

500000 3
816766322 779617142 794227651
3 1
2 1
1 1
3 -1
2 1
2 -1
1 1
1 1
1 1
3 -1
1 -1
2 1
3 1
1 -1
...

output:

950925221

result:

ok "950925221"

Test #20:

score: 5
Accepted
time: 36ms
memory: 10072kb

input:

500000 3
600925621 781710332 540983402
1 -1
1 1
2 1
3 1
1 1
1 1
3 1
3 1
2 -1
3 -1
3 1
1 -1
1 1
2 -1
...

output:

370329204

result:

ok "370329204"