1. 程式人生 > >2017 CCPC 秦皇島 G題

2017 CCPC 秦皇島 G題

題意

給定非負整數n, m(n < 10^1000, 1<= m < 10^100), 把n分成m個非負整數的和

i=1mai=n(ai>=0)
且使
a1 or a2 or a3 … or am最小

題解

1.對於任意i in [1, m]
a1 or a2 or a3 … or am >= ai
當n % m == 0時, 只要存在i in [1, m] ai < n / m
必存在i in [1, m],ai < n / m此時最優是m個數全是n / m, 答案為n / m
2. 當n % m != 0時,
考慮均攤一部分,在處理剩下一部分.
比如n = 1244, m = 10
n / m = 124, n % m = 4.
從1得, n1 = 1240, m = 10答案是124,那麼這種情況答案至少為125.我們可以考慮把1240先均分,把剩餘的4分均給在其中四個.
然後發現可行答案是125.

通用嗎?
3. 考慮這樣一組樣例, n = 314, m = 10
按照2的方法,先均分310得31, 剩餘4個再均分其中四個,預計答案是32,然而卻不正確.
原因是31(11111)的最低為1, 其中一個在加上1就會產生進位
二進位制為100000,這樣結果就是111111等於63.
所以要考慮剩餘部分均攤產生進位的情況.

  1. 我們按照貪心來考慮, 假設均攤有進位.
    進位之後二進位制最右邊一個1在右起第i個位置, 那麼答案最少包含左邊的二進位貢獻, 所以我們可以考慮把左邊的部分先分給m個數(如果左邊大於0一定夠分,反之參照下面5),因為這個貢獻一定有,然後再考慮分剩下的數
    並且前後貢獻互不影響.
  2. 如果左邊是0比如上邊32=100000那麼此時n不能分出m個32就按照32儘可能分配.

這個就是
314 / 10 + 1 = 32
left=314 - 314/32*32 = 26
ans = 32.
然後26 / 10 + 1 = 3
3 = 11B
右起1左邊是 2=10B
left = 26 - 10 * 2 = 6
ans = ans + 2 = 34
left = 6 < 10
ans = ans + 1 = 35
如果left < m且left = 0這個1就不要加了.

java大數搞一搞就可.

import java.util.*;
import java.math.*;

public
class Main { public static void main(String[] args) { BigInteger one = BigInteger.ONE; BigInteger zero = BigInteger.ZERO; Scanner cin = new Scanner(System.in); int T = cin.nextInt(); for(int i = 0; i < T; ++i) { BigInteger n = cin.nextBigInteger(); BigInteger m = cin.nextBigInteger(); if(n.mod(m).equals(zero)) System.out.println(n.divide(m)); else { BigInteger res = zero; while(n.compareTo(zero) == 1) { BigInteger div = n.divide(m).add(one); BigInteger bit = lowbit(div); if(bit.equals(div))//左邊為0 { n = n.subtract(n.divide(div).multiply(div)); res = res.add(div); } else { div = div.subtract(bit); n = n.subtract(div.multiply(m)); res = res.add(div); } } System.out.println(res); } } } public static BigInteger lowbit(BigInteger x) { return x.and(x.multiply(new BigInteger("-1"))); } }