题目
https://ac.nowcoder.com/acm/contest/11160/C
1.莽环节(完全没有干货)
一开始啥都不会只能自己瞎做,瞎做思路:
这是100/i (i属于[1,100])的打表
100 50 33 25 20 16 14 12 11 10 9 8 7 7 6 6 5 5 5 5 4 4 4 4 4 3 3 3 3 3
3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
总结规律发现 count 1 = 100-50, count 2 = 50-33, count 3 = 33-25, count i = list[i-1]-list[i] 直到整个表别遍历完一次
按照这个思路 遍历表,从左右两个方向累加求和
如:
第一轮: sum+= 100*1(1被使用的次数 * 1的值)+ sum(51-100)(出现次数相同的一批数的求和 * 这些数是出现次数)
第二轮:sum+= 50*2 (2被使用的次数 * 2的值)+sum(34-50)(出现次数相同的一批数的求和 * 这些数是出现次数)
直到遍历完整个表得到答案
代码,时间7ms,内存508K
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
typedef long long LL;
int cnt[50000];
int main()
{
LL n;
std::cin >> n;
if(n == 1)
{
std::cout << 1;
return 0;
}
//n=5e4;
LL sum = 0,rec = 0,nD2 = n/2,num,top;
bool judge = false;
for(int i=1; i<=nD2; i++)
{
rec += (n/i)*i;
}
rec += (nD2+1+n)*(n-nD2)/2;
cnt[0] = rec;
cnt[1] = rec/2;
top = rec;
int i;
for(i=1; i<=cnt[i]; i++)
{
cnt[i+1] = rec/(i+2);
num = cnt[i-1]-cnt[i];
sum += (rec/i)*i;
sum += (top+top-num+1)*num*i/2;
if (i == cnt[i]) judge = true;
top -= num;
}
if(!judge)
{
sum+= (rec/i)*i;
}
std::cout << sum ;
return 0;
}
2.整除分块
这是100/i (i属于[1,100])的打表
100 50 33 25 20 16 14 12 11 10 9 8 7 7 6 6 5 5 5 5 4 4 4 4 4 3 3 3 3 3
3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
我们发现有一些相同的数 且 每一块的最右边的数的位置满足 right (100/i) = 100/(100/i) (从1开始计数)
发现1中的个数问题完全可以用整除分块解决, 直接分块求和就可以
代码,时间5ms,内存376K、
#include <iostream>
typedef long long LL;
LL g(LL n)
{
LL sum = 0;
for(LL l=1,r; l<=n; l=r+1)
{
r = n/(n/l);
sum += (l+r)*(r-l+1)*(n/l)/2;
}
return sum;
}
int main()
{
LL n;
std::cin >> n;
std::cout << g(g(n));
return 0;
}
3.其他
抄一个时间2ms的神仙做法,大概有1的思想,正在研究
代码,时间2ms,内存500K
#include <stdio.h>
typedef long long LL;
LL g(LL n){
LL ret = 0;
for(LL i=1;i*i<=n;i++){
LL cnt = n/i-i;
ret += (cnt+1)*i;
ret += (i+1+n/i)*cnt/2;
}
return ret;
}
int main(){
int n;
scanf("%d",&n);
printf("%lld\n",g(g(n)));
}