2020.06.06日常总结——两道思维题

洛谷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 2k1mod123456789!用快速幂算法,可以 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(1in) 对答案的贡献:如果 b b b 中有一个区间 [ l , r ] ( l ≤ i ≤ r ) [l,r](l \leq i \leq r) [l,r](lir) ,则这个区间的总和 ∑ j = l r b j \sum\limits^{r}_{j=l} b_j j=lrbj 会和 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=1nSi×ai

考虑然后 O ( n ) O(n) O(n) 求出所有的 S i ( 1 ≤ i ≤ n ) S_i(1 \leq i \leq n) Si(1in)

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×(ni+1)

g i = g i − 1 + b i × i g_i=g_{i-1}+b_i \times i gi=gi1+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=Si1+figi1

这个式子可以配个图理解一下:

在这里插入图片描述

[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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值