No.1201 お菓子配り-4 - yukicoder
問題
長さ n,m の数列 {ai},{bj} が与えられるので、以下を求めよ (mod109+7) 。
i=1∑nj=1∑mk=1∑bj2⌊bjaik⌋
制約
- 1≤n,m≤2⋅103
- 0≤ai≤108
- 1≤bj≤108
考察
i,j を固定して以下を高速に求めることを考える。
k=1∑b⌊bak⌋
まず切り捨ては考えにくいので、以下のように式変形する。
k=1∑b⌊bak⌋=k=1∑bbak−(akmodb)=bak=1∑bk−b1k=1∑b(akmodb)
前者の ∑ は簡単に 2b(b+1) と分かるので、後者の ∑ を考える。
ここで a,b が互いに素であると仮定する。すると akmodb は k=1,⋯,b で 0,1,⋯,b−1 を一度ずつ経由することが分かる。よって総和は 2b(b−1) となる。
一般の場合でも、 g=gcd(a,b),a′=ga,b′=gb とすれば、 a′,b′ は互いに素なので以下のように変形できる。
k=1∑b(akmodb)=gk=1∑b(a′kmodb′)=g2k=1∑b′(a′kmodb′)=21g2b′(b′−1)=21b(b−g)
以上を整理すると、以下の通り。
k=1∑b2⌊bak⌋=b2ak=1∑bk−b2k=1∑b(akmodb)=ba⋅b(b+1)−b1⋅b(b−g)=a(b+1)−(b−g)=ab+a−b+g
実装例
#543046 (C++17) No.1201 お菓子配り-4 - yukicoder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#include <iostream>
#include <numeric>
#include <vector>
template <int MOD>
struct ModInt { ... };
constexpr int MOD = 1000000007;
using mint = ModInt<MOD>;
using lint = long long;
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<lint> xs(n), ys(m);
for (auto& x : xs) std::cin >> x;
for (auto& y : ys) std::cin >> y;
mint ans = 0;
for (auto a : xs) {
for (auto b : ys) {
ans += a * b + a - b + std::gcd(a, b);
}
}
std::cout << ans << "\n";
}
|