原题传送门
首先要发现一个性质
令
s
u
m
a
=
∑
i
=
1
n
a
i
,
s
u
m
b
同
理
suma=\sum_{i=1}^na_i,sumb同理
suma=∑i=1nai,sumb同理
答案的上界
=
[
(
s
u
m
a
+
s
u
m
b
)
k
]
=[\frac{(suma+sumb)}{k}]
=[k(suma+sumb)]
下界
=
[
s
u
m
a
k
]
+
[
s
u
m
b
k
]
=[\frac{suma}{k}]+[\frac{sumb}{k}]
=[ksuma]+[ksumb]
上界
<
=
<=
<=下界+1,即要么上界=下界,要么上界=下界+1
证明略,发现这个上界的这个策略可能是达不到的,下界的这个方法是一定可以达到的,所以当上界=下界的时候,直接输出。但是如果上界=下界+1,那么因为下界的策略是取同一类型的,就考虑是否可以通过同一棵树上取一些东西使得取到上界的值
令
s
u
m
a
suma
suma%
k
=
r
a
,
s
u
m
b
k=ra,sumb
k=ra,sumb%
k
=
r
b
k=rb
k=rb
若存在通过同一棵树上取下来这种策略的总数
(
x
a
,
x
b
)
(xa,xb)
(xa,xb),就是
a
a
a取了
x
a
xa
xa个,
b
b
b取了
x
b
xb
xb个,并且满足
x
a
xa
xa%
k
<
=
r
a
,
x
b
k<=ra,xb
k<=ra,xb%
k
<
=
r
b
k<=rb
k<=rb,那么就能取到上界
把上述条件转化,
x
b
xb
xb%
k
=
k
−
(
x
a
k=k-(xa
k=k−(xa%
k
)
<
=
r
b
k)<=rb
k)<=rb,所以只要存在一个
x
a
xa
xa使得
x
a
xa
xa%
k
k
k属于
[
k
−
r
b
,
r
a
]
[k-rb,ra]
[k−rb,ra]就行了
这个可以用
d
p
i
dp_{i}
dpi表示当前是否存在一个
x
a
,
x
a
xa,xa
xa,xa%
k
=
i
k=i
k=i,用01背包可以求出来
只要存在一个这样的
i
i
i属于
[
k
−
r
b
,
r
a
]
[k-rb,ra]
[k−rb,ra]就能达到上界
接下来证明
[
s
u
m
a
k
]
=
m
0
,
[
s
u
m
b
k
]
=
n
0
[\frac{suma}{k}]=m0,[\frac{sumb}{k}]=n0
[ksuma]=m0,[ksumb]=n0
[
x
a
k
]
=
m
,
[
x
b
k
]
=
n
[\frac{xa}{k}]=m,[\frac{xb}{k}]=n
[kxa]=m,[kxb]=n
[
s
u
m
a
−
x
a
k
]
=
m
0
−
m
,
[
s
u
m
b
−
x
b
k
]
=
n
0
−
n
[\frac{suma-xa}{k}]=m0-m,[\frac{sumb-xb}{k}]=n0-n
[ksuma−xa]=m0−m,[ksumb−xb]=n0−n
[
x
a
+
x
b
k
]
=
x
a
+
x
b
k
=
m
+
n
+
1
[\frac{xa+xb}{k}]=\frac{xa+xb}{k}=m+n+1
[kxa+xb]=kxa+xb=m+n+1
成立
Code:
#include <bits/stdc++.h>
#define maxn 1010
#define LL long long
using namespace std;
int a[maxn], b[maxn], dp[maxn], n, k;
LL suma, sumb;
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
int main(){
n = read(), k = read();
for (int i = 1; i <= n; ++i) suma += a[i] = read(), sumb += b[i] = read();
if ((suma + sumb) / k == (suma / k + sumb / k)) return printf("%lld\n", (suma + sumb) / k), 0;
LL r = suma % k, l = k - sumb % k;
dp[0] = 1;
for (int t = 1; t <= n; ++t){
for (int i = k - 1; i >= 0; --i)
if (dp[i]) for (int j = 1; j < k; ++j)
if (j <= a[t] && k - j <= b[t]) dp[(i + j) % k] = 1;
for (int i = l; i <= r; ++i) if (dp[i]) return printf("%lld\n", (suma + sumb) / k), 0;
}
printf("%lld\n", suma / k + sumb / k);
return 0;
}