下午有时间于是又做了下Round E, 算法太弱导致只做了前三道,记录下。
- A. Diwali lightnings
- B. Beautiful Numbers
- C. Partioning Number
A. Diwali lightnings
送分题,循环序列统计B出现了多少次,注意边界条件即可,略过
B. Beautiful Numbers
题目就不贴了,可以去codejam上去看,给定一个数N,求一个进制K,使N在K进制下可以表示为连续的1。
暴力法可以通过小数据,但最大10^19次方显然无法通过。设K进制表示下有m个1,m最大为64(2进制),最小为2(N-1进制)。
N = K^(m-1)+K^(m-2)+…+K+1
当m确定时,N是K的单调递增函数,因此可以用二分法解决,最终时间复杂度是64*O(logN),编程时注意枚举m时,上界是n,可能有溢出的问题,注意。贴下代码,但似乎有些BUG会溢出,欢迎讨论:
#include <iostream>
using namespace std ;
typedef unsigned long long ull ;
ull m, n ;
int T ;
ull work(){
for(m=64 ;m>=2 ;m--) {
ull lk = 2;
ull hk = n-1;
while (lk<=hk) {
ull mk = lk/2+hk/2 ;
if(lk%2==1 && hk%2==1)
mk++ ;
ull res = 0 ;
ull tmp = 1 ;
bool legal = true ;
for(int j=0 ;j<m ;j++){
ull tr = res+tmp ;
if(tr<res || tr<tmp){
//!溢出
legal = false ;
break ;
}
res = tr ;
ull ttmp = tmp*mk ;
if(ttmp<tmp || ttmp<mk){
legal= false ;
break ;
}
tmp = ttmp ;
}
if(!legal || res>n){
hk = mk-1 ;
continue ;
}
if(res==n){
return mk ;
}
if(res<n){
lk = mk+1 ;
continue ;
}
}
}
}
int main() {
cin >> T ;
for(int i=0 ;i<T ;i++) {
cin >> n ;
cout << "Case #" << i+1 << ": " ;
ull res = work() ;
cout << res << endl ;
}
}
C. Partioning Number
题意比较长,不再赘述,要求将N个球放到多个桶里面即把数N分割为多个正整数,形成一个序列,要求:
- 第一个数被D整除
- 所有的数字相差小于等于2,即只能有三个不同的数字
- non-decreasing
根据分析我们可以知道第一个数字x只能是D的整倍数,同时后面只能由x+1和x+2,我们设三种不同的数字的个数分别为a,b,c,有多少种满足条件的a,b,c就是结果。
有: a*x+b*(x+1)+c*(x+2) = N
a > 0, b >=0, c>=0
我们可以枚举a,b再加上枚举x共三层循环。大数据会超时
考虑如何降低,我们整理方程:
(a+b+c)*x+b+2c = N
令 p = a+b+c, q = b+2c , 此外 q = N-p*x
由于a>0 则有约束: b+c< p, b+2c=q
这就是一个线性规划问题,求b+2c=q这条直线上有多少个整数点满足b+c< p。很简单的线性规划,注意一些边界条件,例如c是否整数,边界上的点是否满足,b>0, c>0等。假设交点是(b0,c0)几个分界点,b0=0, b0=p等
AC代码
#include <iostream>
using namespace std ;
int T, N, D ;
int work(){
int ans = 0 ;
for(int x=D ;x<=N ;x+=D){
int ma = N/x ;
for(int p=1 ;p<=ma ;p++) {
int q = N-p*x ;
int mb = 2*p-q ;
if(mb<= 0)
continue ;
if(mb>p) {
if(q>=0) {
ans += (q + 1) / 2;
if (q % 2 == 0)
ans++;
}
}
else {
ans += mb / 2;
if (q % 2 == 1 && mb%2==0)
ans--;
}
}
}
return ans ;
}
int main() {
cin >> T ;
for (int t=1 ;t<=T ;t++){
cin >> N >> D ;
cout << "Case #" << t << ": " ;
int res = work() ;
cout << res << endl ;
}
}