洛谷P5035 金坷垃 \color{green}{\texttt{洛谷P5035 金坷垃}} 洛谷P5035 金坷垃
[problem] \color{blue}{\texttt{[problem]}} [problem]
假设现在又一个
x
x
x,下一秒
x
x
x 可以减去自己的一个约数(但是同一个数不能被同时被减多次)。比如
10
10
10 可以减
2
2
2 变成
8
8
8,但是
8
8
8 不能再减
2
2
2 变成
2
2
2,因为
2
2
2 已经用过了。如果
x
x
x 可以通过若干次变化变成
1
1
1,则我们叫
x
x
x 为 好数
,求第
k
k
k 小的 好数
对
123456789
123456789
123456789 取模的结果。
[Solution] \color{blue}{\texttt{[Solution]}} [Solution]
正难则反,直接想哪些数可以变化得到 1 1 1 不好想,我们考虑从 1 1 1 可以变化到哪些数。
很简单,我们发现只有 2 2 2 才能转移到 1 1 1。然后我们考虑哪些数可以转移到 2 2 2。
因为 1 1 1 已经被用过了,所以我们发现只有 4 4 4 才可以转移到 2 2 2(本来 3 3 3 也可以的,但是 1 1 1 已经用过了)。同理, 4 4 4 只能由 8 8 8 转移来, 8 8 8 只能由 16 16 16 转移来……
发现了什么?没错,答案就是 2 k − 1 m o d 123456789 2^{k-1} \bmod 123456789 2k−1mod123456789!用快速幂算法,可以 O ( log k ) O(\log k) O(logk) 解决这道题。
[code] \color{blue}{\texttt{[code]}} [code]
洛谷P5686 [CSP-SJX2019]和积和 \color{green}{\texttt{洛谷P5686 [CSP-SJX2019]和积和}} 洛谷P5686 [CSP-SJX2019]和积和
[problem] \color{blue}{\texttt{[problem]}} [problem]
[Solution] \color{blue}{\texttt{[Solution]}} [Solution]
我们考虑 a i ( 1 ≤ i ≤ n ) a_i(1 \leq i \leq n) ai(1≤i≤n) 对答案的贡献:如果 b b b 中有一个区间 [ l , r ] ( l ≤ i ≤ r ) [l,r](l \leq i \leq r) [l,r](l≤i≤r) ,则这个区间的总和 ∑ j = l r b j \sum\limits^{r}_{j=l} b_j j=l∑rbj 会和 a i a_i ai 相乘恰好一次。
记所有与 a i a_i ai 相乘的区间的和为 S i S_i Si。则总答案为:
∑ i = 1 n S i × a i \sum\limits_{i=1}^{n} S_i \times a_i i=1∑nSi×ai
考虑然后 O ( n ) O(n) O(n) 求出所有的 S i ( 1 ≤ i ≤ n ) S_i(1 \leq i \leq n) Si(1≤i≤n)。
记 f i f_i fi 表示 b b b 中所有左端点为 i i i 的区间的和的总和,同理 g i g_i gi 表示 b b b 中所有右端点为 i i i 的区间的和的总和。我们有:
f i = f i + 1 + b i × ( n − i + 1 ) f_i=f_{i+1}+b_i \times (n-i+1) fi=fi+1+bi×(n−i+1)
g i = g i − 1 + b i × i g_i=g_{i-1}+b_i \times i gi=gi−1+bi×i
即在原来的区间的基础上,把所有区间加上 b i b_i bi 这么个数,就可以得到 f i f_i fi 和 g i g_i gi。
则我们有:
S i = S i − 1 + f i − g i − 1 S_i = S_{i-1}+f_i-g{i-1} Si=Si−1+fi−gi−1
这个式子可以配个图理解一下:
[code] \color{blue}{\texttt{[code]}} [code]
const int N=5e5+100;
const int mod=1e9+7;
#define ll long long
ll S[N],f[N],g[N],ans;
int a[N],b[N],n;//O(N)
int main(){
freopen("t1.in","r",stdin);
n=read();g[0]=S[0]=f[n+1]=0;
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) b[i]=read();
for(int i=n;i>=1;i--)
f[i]=(f[i+1]+1ll*b[i]*(n-i+1)%mod)%mod;
for(int i=1;i<=n;i++)
g[i]=(g[i-1]+1ll*b[i]*i%mod)%mod;
for(int i=1;i<=n;i++)
S[i]=((S[i-1]+f[i])%mod-g[i-1]+mod)%mod;
for(int i=1;i<=n;i++)
ans=(ans+S[i]*a[i]%mod)%mod;
printf("%lld",ans);
return 0;
}