Educational Codeforces Round 7

题目链接:https://codeforces.com/contest/622

A - Infinite Sequence

签到题

B - The Time

签到题

C - Not Equal on a Segment

题意:给一个n个数的数组,然后若干次询问,每次询问一个(l,r,x),问区间[l,r]中有没有不等于x的数,假如有,输出任意一个。

题解:反过来dp,每个数维护“下一个与其不等或者是数组结尾”的数的位置,那么先看a[l]是不是满足a[l]!=x,若是,则输出,否则a[nxt[l]]就是最近的下一个不是x的位置,这个位置假如超过r,就不存在,否则这个位置是其中一种解。

D - Optimal Number Permutation

很有意思的一个构造。

题意:给一个2n个数的数组,由两个n个数的排列打乱而成。显然[1,n]每个数出现两次,第 \(i\) 个数两次出现的位置之间的差定义为 \(d_i\) 最小化 \(\sum\limits_{i=1}^{n}(n-i)|d_i+i-n|\)

题解:要使得上式最小,是要通过调整每个数两次出现的间隔,构造了好几种以1开头的,发现都可以使得和为0,但是没什么规律:

n=8
1x2x3x41234xxxxx
1626384123485775

构造的思路是使得中间一段是从1开始连续自然数,但是这样不知道具体的规律是什么。

想了很久,突然想试试反过来,从大到小构造,那么

n=8
1357753182468642

非常有规律,显然这样构造也会使得和为0。

扫描二维码关注公众号,回复: 9980866 查看本文章

具体实现的时候,用两个deque从大到小两头push,然后再for一遍输出。假如要复杂度严格线性的算法,可以直接1357...这样输出。

注意是n-1那个中间不需要加东西,n-2那个中间放个n。

F - The Sum of the k-th Powers

题意:求[1,n]的正整数的k次方和。1<=n<=1e9,0<=k<=1e6。即 \(\sum\limits_{i=1}^{n}i^k\)

题解:易知k次方和是一个k+1次多项式,求出[1,k+2]个点,可以 \(O(k^2)\) 插值出k+1次多项式。假如选出的点的横坐标是连续整数,可以 \(O(k)\) 插值出k+1次多项式。

详见:拉格朗日插值

拉格朗日插值: \(f(x)=\sum\limits_{i=1}^{n}y_i\frac{\prod\limits_{j=1,j\neq i}^{n}x_j-x}{\prod\limits_{j=1,j\neq i}^{n}x_j-x_i}\)

这个模板传入的参数:需要插值n次多项式,传入x[0]~x[n]共n+1个点(*x就是&x[0]),y同理,求出横坐标为xi的函数值。

先线性预处理出差的前缀积和后缀积(其实前缀积可以不用存下来,转移的时候直接乘上去就可以,但是后缀积建议存下来,因为不一定可能通过好的办法求出乘法逆元(甚至乘法逆元不存在)),然后就可以直接求出分子的值。分母必定是两个阶乘的乘积,而且其正负号相间。

例如,假设这一段连续的正整数为:

\([1,2,3,4,5,6]\)

那么分母的值分别是:

\((2-1)(3-1)(4-1)(5-1)(6-1)=+0!5!\)
\((1-2)(3-2)(4-2)(5-2)(6-2)=-1!4!\)
\((1-3)(2-3)(4-3)(5-3)(6-3)=+2!3!\)
\((1-4)(2-4)(3-4)(5-4)(6-4)=-3!2!\)
\((1-5)(2-5)(3-5)(4-5)(6-5)=+4!5!\)
\((1-6)(2-6)(3-6)(4-6)(5-6)=-5!0!\)

以此类推。

ll qpow(ll x, ll n) {
    ll res = 1;
    while(n) {
        if(n & 1)
            res = res * x % MOD;
        x = x * x % MOD;
        n >>= 1;
    }
    return res;
}
 
ll x[1000005], y[1000005];
ll s1[1000005], s2[1000005];
ll ifac[1000005];
 
ll lagrange(int n, ll *x, ll *y, ll xi) {
    ll ans = 0;
    s1[0] = (xi - x[0]) % MOD, s2[n + 1] = 1;
    for (int i = 1; i <= n; i++)
        s1[i] = 1ll * s1[i - 1] * (xi - x[i]) % MOD;
    for (int i = n; i >= 0; i--)
        s2[i] = 1ll * s2[i + 1] * (xi - x[i]) % MOD;
    ifac[0] = ifac[1] = 1;
    for (int i = 2; i <= n; i++)
        ifac[i] = -1ll * MOD / i * ifac[MOD % i] % MOD;
    for (int i = 2; i <= n; i++)
        ifac[i] = 1ll * ifac[i] * ifac[i - 1] % MOD;
    for (int i = 0; i <= n; i++) {
        (ans += 1ll * y[i] * (i == 0 ? 1 : s1[i - 1]) % MOD * s2[i + 1] % MOD
                * ifac[i] % MOD * (((n - i) & 1) ? -1 : 1) * ifac[n - i] % MOD) %= MOD;
    }
    return (ans + MOD) % MOD;
}
 
void test_case() {
    ll n, k;
    scanf("%lld%lld", &n, &k);
    for(int i = 1; i <= k + 2; ++i) {
        x[i] = i;
        y[i] = qpow(i, k);
        y[i] = (y[i] + y[i - 1]) % MOD;
    }
    printf("%lld\n", lagrange(k + 1, x + 1, y + 1, n));
}

猜你喜欢

转载自www.cnblogs.com/KisekiPurin2019/p/12529360.html
今日推荐