上次做过类似的题,原来这道还要简单些??
上次那道题是每天可以同时买进卖出,所以用两个优先队列,一个存买进,一个存卖出(供反悔的队列)。
这道题实际上用一个就够了???但是不好理解!!
所以我还是用了俩...
和之前那道题不同的是,如果我选择了反悔,之前第二个队列的队头就完全没有用了,但是我们可以选择重新买它,所以把它重新放到第一个队列。
#include<bits/stdc++.h> using namespace std; priority_queue < int, vector < int >, greater < int > > q1, q2; int n, a[100005]; long long ans; int main() { freopen("trade.in", "r", stdin); freopen("trade.out", "w", stdout); scanf("%d", &n); for(int i = 1; i <= n; i ++) scanf("%d", &a[i]); for(int i = 1; i <= n; i ++) { int x1, x2, r1 = 0, r2 = 0; if(!q1.empty()) { x1 = q1.top(); if(a[i] - x1 > 0) r1 = a[i] - x1; } if(!q2.empty()) { x2 = q2.top(); if(a[i] - x2 > 0) r2 = a[i] - x2; } if(r1 >= r2 && r1) { q1.pop(); q2.push(a[i]); ans += r1; } else if(r2 > r1 && r2 ) { q2.pop(); q2.push(a[i]); q1.push(x2); ans += r2; } else q1.push(a[i]); } printf("%lld", ans); return 0; }
这道题乍一看是推公式$O(1)$的数论??经$yuli$dalao考场上一个多小时的测试发现没有这样的式子....
所以$zc$dalao通过研究打表发现了正解!其实是莫队!
???
首先我们也来打一下表....发现了两个递推式:$S_n^m=S_n^{m-1}+C_n^m$和$S_n^m=2S_{n-1}^m-C_{n-1}^m$,我们可以把$[n,m]$看成一个区间来进行离线莫队转移,复杂度$O(n\sqrt{n})$。
#include<bits/stdc++.h> #define mod 1000000007 #define LL long long using namespace std; int blo[100005]; struct Node { int n, m, id; } qus[100005]; bool cmp(Node a, Node b) { if(blo[a.m] == blo[b.m]) return a.n < b.n; return a.m < b.m; } LL fac[100005], inv[100005]; LL C(int n, int m) { if(m > n) return 0; return fac[n] * inv[m] % mod * inv[n - m] % mod; } LL mpow(LL a, LL b) { LL ans = 1; for(; b; b >>= 1, a = a * a % mod) if(b & 1) ans = ans * a % mod; return ans; } void init() { fac[0] = 1; inv[0] = 1, inv[1] = 1; for(int i = 1; i <= 100005; i ++) fac[i] = fac[i - 1] * i % mod; for(int i = 2; i <= 100005; i ++) inv[i] = mpow(fac[i], mod - 2); for(int i = 1; i <= 100005; i ++) blo[i] = i/300 + 1; } int Ans[100005]; int main() { freopen("sum.in", "r", stdin); freopen("sum.out", "w", stdout); int id; scanf("%d", &id); init(); int T; scanf("%d", &T); for(int i = 1; i <= T; i ++) scanf("%d%d", &qus[i].n, &qus[i].m), qus[i].id = i; sort(qus + 1, qus + 1 + T, cmp); int n = qus[1].n, m = qus[1].m; LL ans = 0; for(int i = 0; i <= m; i ++) ans = (ans + C(n, i)) % mod; Ans[qus[1].id] = ans; for(int i = 2; i <= T; i ++) { while(qus[i].m < m) { ans = (ans - C(n, m) + mod) % mod; m --; } while(qus[i].n > n) { ans = (2LL * ans % mod - C(n, m) + mod) % mod; n ++; } while(qus[i].m > m) { m ++; ans = (ans + C(n, m)) % mod; } while(qus[i].n < n) { n --; ans = 1LL * (ans + C(n, m)) * inv[2] % mod; } Ans[qus[i].id] = ans; } for(int i = 1; i <= T; i ++) printf("%d\n", Ans[i]); return 0; }