1003 Calculate

题意:给定x1,x2,y1,y2,计算中超热身赛(2021湘潭全国邀请赛-重现)补题_子序列,模数为1e9+7

T <= 100, 1 <= x1 <= x2 <= 1e9, 1 <= y1 <= y2 <= 1e9

solution:

暴力展开,对于∑i / x1,能够O(1)计算

对于∑x2 / i 这项, 对10 / i 进行分析, 10 / i 的ans分别为 10 5 3 2 2 1 1 1 1 1

可以发现10 / i 的ans一共有5种:10,5,3,2,1,而不是10种,对于小的ans,出现了多次,且ans的值是连续的,对于大的ans,ans的值不连续且只出现一次

我们把ans * ans > x2 的 ans称为大值,其余ans为小值,可以算出大值和小值都是sqrt(x2)个,对于大值,都只出现1次,对于每个小值,可以O(1)计算出这个小值出现的次数

这样我们就能O(sqrt(n))计算出∑x2 / i 这项了 

对于所有包含x2 / i 这种类型的项,我们按也ans = x2 / i 的值分块,分成sqrt(x2)个大值块和sqrt(x2)个小值块

 



#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const long long MOD = 1e9+7;
long long qpow(long long n,long long p){
long long res = 1;
for(;p;p>>=1,n = n * n % MOD){
if(p&1) res = res * n % MOD;
}
return res;
}
long long inv(long long x) {
return qpow(x,MOD-2);
}
long long suan01(long long x1,long long x2){// (i/x1)
if(x2 < x1) return 0;
long long up = x2 / x1 - 1;
long long re = x2 - x1 + 1 - x1 * up;
long long res = 0;
res += re * (up + 1) % MOD;
if(up) res += x1 * (up) % MOD * (up + 1) % MOD * inv(2) % MOD;
res %= MOD;
return res;
}
long long suan1(long long x1,long long x2){// (i/x1)^2
long long up = x2 / x1 - 1;
long long re = x2 - x1 + 1 - x1 * up;
long long res = 0;
res += re * (up+1) % MOD * (up+1) % MOD;
if(up) res += x1 * up % MOD * (up + 1) % MOD * (up * 2 + 1) % MOD * inv(6) % MOD;
res %= MOD;
return res;
}
long long suan02(long long x1,long long x2){//(x2 / i)
long long res = 0;
long long dd = x2 / x1;
for(long long i = x1;i * i <= x2;i++){
res += dd;
dd = x2 / (i + 1);
}
long long l,r;
for(;dd;dd--){
l = x2 / (dd+1) + 1;
l = max(l,x1);
r = x2 / dd;
res += (r - l + 1) * dd;
}
res %= MOD;
return res;
}
long long suan2(long long x1,long long x2){// (x2 / i) ^ 2
long long res = 0;
long long dd = x2 / x1;
for(long long i = x1;i * i <= x2;i++){
res += dd * dd % MOD;
dd = x2 / (i + 1);
}
long long l,r;
res %= MOD;
for(;dd;dd--){
l = x2 / (dd + 1) + 1;
l = max(l,x1);
r = x2 / dd;
res += (r - l + 1) * dd * dd ;
}
res %= MOD;
return res;
}
long long suan3(long long x1,long long x2){//2 * (i / x1) * (x2 / i)
long long res = 0;
long long dd = x2 / x1;
for(long long i = x1;i * i <= x2;i++){
res += dd * 2 * (i / x1);
dd = x2 / (i + 1);
}
long long l,r;
for(;dd;dd--){
l = x2 / (dd + 1) + 1;
l = max(l,x1);
r = x2 / dd;
res += dd * 2 * ((suan01(x1,r) - suan01(x1,l-1) + MOD) % MOD);
}
res %= MOD;
return res;
}
int main()
{
int T;
cin>>T;
long long x1,x2,y1,y2;
while(T--){
scanf("%lld%lld%lld%lld",&x1,&x2,&y1,&y2);
long long ans = 0;
long long res1 = suan01(x1,x2);
long long res2 = suan02(x1,x2);
long long res3 = suan01(y1,y2);
long long res4 = suan02(y1,y2);
ans += (y2 - y1 + 1) * (suan1(x1,x2) + suan2(x1,x2)) % MOD + (x2 - x1 + 1) * (suan1(y1,y2) + suan2(y1,y2)) % MOD;
ans %= MOD;
ans += (y2 - y1 + 1) * suan3(x1,x2) + (x2 - x1 + 1) * suan3(y1,y2);
ans %= MOD;
ans += (res1 * res3 + res1 * res4 + res2 * res3 + res2 * res4) * 2;
ans %= MOD;
printf("%lld\n",ans);
}
return 0;
}


 

1009 Sequence

题意:给定a[n], 一个序列的贡献为在这个序列里只有一个的数的个数,要求把a[n]分成m份子序列(子序列连续),求m份子序列的贡献之和最大是多少

1 <= a[i] <= n,  2 <= m <= min(10,n),n <= 2e5

思路明天写。。。