• 牛客练习赛42D(性质、数学)


    题目传送

    就像题解所说的,写几个可以发现有分成四段的性质:第一段是从n开始往下贪,第二段是个数字,第三段……卧槽好吧真难描述。

    然后发现这个数据量可达1e9,所以考虑“二分确定序列+数学计算”的方式解题。

    首先二分出第一段的长度,这里我写得丑了,又将某些情况特判了一下;不难发现有了第一段的长度、N、K这三个量,序列已确定。

    然后疯狂手推数学公式把这四段的值求出来,特殊情况的例子很好举,自己调一调打打补丁做一做膜法,大概就莽A了吧……不过要是在考场上本垃圾就必死无疑了。

     1 #include <cstdio>
     2 #include <cmath>
     3 #include <iostream>
     4 using namespace std;
     5 
     6 typedef long long ll;
     7 const ll mod = 1e9 + 7;
     8 ll N, K, x, ans1, ans2, ans3, ans4;
     9 
    10 ll add(ll a, ll b) {
    11     return a + b >= mod ? a + b - mod : a + b;
    12 }
    13 
    14 ll sub(ll a, ll b) {
    15     return a - b < 0 ? a - b + mod : a - b;
    16 }
    17 
    18 ll ksm(ll a, ll b) {
    19     ll ret = 1;
    20     for (; b; b >>= 1) {
    21         if (b & 1)    ret = ret * a % mod;
    22         a = a * a % mod;
    23     }
    24     return ret;
    25 }
    26 
    27 inline ll cal(ll l, ll r) {
    28     return (l + r) * (r - l + 1) / 2;
    29 }
    30 
    31 inline ll cal2(ll n) {//这是求x + 2*x^2 + ... + n*x^n的函数
    32     ll a = n % mod * ksm(x, n + 1) % mod * (x - 1) % mod;
    33     ll b = x * sub(ksm(x, n), 1) % mod;
    34     return sub(a, b) * ksm((x - 1) * (x - 1) % mod, mod - 2) % mod;
    35 }
    36 
    37 int main() {
    38     cin >> N >> K;
    39     x = N + 1;
    40     if (K == 0) {
    41         cout << cal2(N) << endl;
    42         return 0;
    43     }
    44     ll l = 1, r = N;
    45     while (l < r) {
    46         ll mid = (l + r) >> 1;
    47         if (cal(N - mid, N - 1) <= K)    l = mid + 1;
    48         else    r = mid;
    49     }
    50     while (cal(N - l, N - 1) >= K)    l--;//至此l为第一段长度。如果出现54312这种,会将54作为第一段,3作为第二段,12为第三段,第四段为空
    51     if (l) {
    52         ans1 = add(sub(x * x % mod * (ksm(x, l) - 1 + mod) % mod * ksm(x - 1, mod - 2) % mod, l * x % mod), (N - l) * x % mod * (ksm(x, l) - 1 + mod) % mod) * ksm(x - 1, mod - 2) % mod;
    53         K -= cal(N - l, N - 1);
    54     }
    55     if (K) {
    56         K++, l++;//K就是第二段那个数字,l++只是为了运算简便
    57         ans2 = K % mod * ksm(x, l) % mod;
    58         ans3 = ksm(x, l) * cal2(K - 1) % mod;
    59         if (N - l + 1 > K) {//如果有第四段
    60             ll tmp = K % mod * sub(ksm(x, N + 1), ksm(x, K + l)) % mod * ksm(x - 1, mod - 2) % mod;
    61             ans4 = add(tmp, ksm(x, K + l - 1) * cal2(N - K - l + 1) % mod);
    62         }
    63     }
    64     cout << (ans1 + ans2 + ans3 + ans4) % mod;
    65     return 0;
    66 }
  • 相关阅读:
    Dockerfile编写语法
    java应用测试报告生成(二):利用ant的build.xml生成测试报告
    java应用测试报告生成(一): sonarqube配合Jenkins生成测试报告及覆盖率
    cannot create windows service for mysql
    线程交互:生产消费模型
    线程同步与锁
    线程的五种状态及改变状态的三种方法
    简单的git入门介绍及常用操作
    CentOS/RHEL 7中的firewall控制
    oracle数据库兼容mysql的差异写法
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10551433.html
Copyright © 2020-2023  润新知