其他分享
首页 > 其他分享> > 牛客练习赛42D(性质、数学)

牛客练习赛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 }

 

标签:练习赛,return,sub,ll,42D,牛客,ksm,第一段,mod
来源: https://www.cnblogs.com/AlphaWA/p/10551433.html