NC14731 逆序对

题目

题目描述

求所有长度为 \(n\)\(01\) 串中满足如下条件的二元组个数:
设第 \(i\) 位和第 \(j\) 位分别位 \(a_i\)\(a_j\) \((i<j)\) ,则 \(a_i=1,a_j=0\)
答案对1e9+7取模。

输入描述

输入一个 \(n\)

输出描述

输出答案对1e9+7取模

示例1

输入

3

输出

6

说明

img

备注

\(n \leq 10^{18}\)

题解

知识点:计数dp,运算优化。

推个公式,设\(f(n)\) 是长度为 \(n\) 时的逆序对总数,推导如下:

因为长度加一,则可以认为首位 \(1\)\(0\)\(n-1\) 情况的排列组合。由于 \(10\) 两种情况,那么 \(f(n-1)\) 会出现两次; \(1\)\(n-1\) 所有情况的 \(0\) 都会产生一组逆序对,所以只要求出 \(n-1\)\(0\) 出现次数,一共有 \(2^{n-1}\) 种长度为 \(n-1\) 的串数字,则数字总数是 \((n-1)2^{n-1}\) ,注意到 \(1\)\(0\) 各占一半,则 \(0\) 的总数是 \((n-1)2^{n-2}\)

综上有 \(f(n) = 2f(n-1) + (n-1)2^{n-2}\),解递推得公式 \(f(n) = \frac{n(n-1)}{2}\cdot 2^{n-2}\)

用快速幂运算,注意 \(n=1\) 的特殊情况,以及取模问题,\(500000004 \cdot 2 \equiv 1 (mod \ 1000000007)\)

时间复杂度 \(O(\log n)\)

空间复杂度 \(O(1)\)

代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int mod = 1e9 + 7;

ll qpow(ll a, ll k) {
    ll ans = 1;
    while (k) {
        if (k & 1) ans = a * ans % mod;
        k >>= 1;
        a = a * a % mod;
    }
    return ans;
}

///用不着分治,解递推得到通项

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    ll n;
    cin >> n;
    int ans = (n % mod) * ((n - 1) % mod) % mod * 500000004 % mod * qpow(2, max(n - 2, 0LL)) % mod;
    cout << ans << '\n';
    return 0;
}
posted @ 2022-06-23 20:10  空白菌  阅读(42)  评论(0编辑  收藏  举报