D:对于Σi^2,求前n项和,1~n是不是完全平方数。
心路历程:上面前n项和的公式为 n (n+1) (2n+1) / 6,直接用double计算wa了,精度不够。
用long long存储n的话可以ac,但是应该是数据没有想到(longlong溢出后还是可能是一个完全平方数)
只有1和24,严格证明实在不会。
B:你现在有n*m个口罩,你需要把这n * m个口罩装箱,保证可以平均分给n个医院或者m个医院,使得箱子数目最少。
队友A的,回来补上
假设n < m,所以,每个箱子最多n个(一旦大于n,那么分给m个医院每个医院n个。就会超出需求)
自己的错误: 贪心地用每个箱子n个去满足n个医院每家m个口罩,最后补上 m%n。但是这样子导致箱子只有n与m%n两种。
虽然可以满足n个医院都分到m个口罩,但是分给m个医院n个口罩,不一定可以用m%n正好凑出n来。
题目正解:
对于分给n个医院,每个医院需要m个: m/n个包装为n的箱子 + m%n的一个箱子
对于分给m个医院,每个医院需要n个:上述条件可以满足 m/n个医院(每个医院分到n的箱子),但是还有m%n个医院没有口罩
即:第一步分完之后,还剩下(m%n)* n个口罩没有发。
分给n的医院的:还剩下n个医院没有满足(都差m%n)
分给m个医院的:还剩下m%n个医院没有满足(都差n)。
所以,可以理解为 newn = m%n, newm = n。
即:在本次分配之后
对于分给n个医院:n个医院都还差m%n,也就是newn
对于分给m个医院:有m%n个医院还差n
可以理解为: 第二次分配是: 将(m%n)* n个口罩平均分给 n个医院,或分给m%n个医院
同上进行第二步计算。
写一个dfs(类似于gcd)即可。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int ans;
vector<int> v;
void dfs(int n, int m)
{
if(n == 0) return;
int num = m / n;
for(int i = 1; i <= n * num; i++)
{
v.push_back(n);
}
ans += m / n * n;
dfs(m%n,n);
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
{
int n,m;
cin >> n >> m;
v.clear();
ans = 0;
if(n > m)
{
swap(n,m);
}
dfs(n,m);
cout << ans << endl;
for(int i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
cout << endl;
}
return 0;
}
H:根据题意,计算在n,k范围内有多少对满足条件。
数论,看看算了。
数对(n,k)是有效地,只需要满足一下任意一个条件即可
- n等于1
- n为k的倍数,也就是n%k=0
- n-1为k的倍数(从n=1推算:(1+k,k)也是有效的,以此类推)
由于n,k的范围过大,需要使用整除分块进行优化
整除分块是什么呢?
在计算∑ n / i 时,由于n, i为正数,会存在一段的 n/i 相等。我们可以对其加以利用来优化o(n)的暴力
for(int i=1,j; i <= n; i = j + 1)
{
j = n / (n/i);
ans +=(j-i+1)*(n/i);
}
首先对于i,从1到n开始枚举。
j = n / ( n / i ); n / i 为当前 i 的值,再用n去除n / i得到 j, 这时 j * (n/i) <= n且j为最大
还不懂?
假如n = 10,那么当 i 枚举到6的时候,10 / 6 = 1.那么 10 / 1 = 最大的i(当n/i=1固定时)
所以得知 6 ~ 10 是 n / i 相等的一块
通过手算可以知道 6 ~ 10的 n / i 都是1。成立
得到n/i相等的最后一位, 那么 j - i + 1 就是这段相同块的长度,值都是n/i。
下一次循环,i直接跳到 j 的后一位,即可。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int mod = 1e9 + 7;
long long ans = 0;
long long n,k;
void solve(long long a)
{
long long i,j;
for(i = 2; i <= min(a,k);i=j+1)
{//从2开始避免重复计算
//取n和k的最小值即可
j = min(a/(a/i),k);
//只计算前k项,所以最后一位避免超过k
ans += (j - i + 1) % mod *( a / i ) % mod;
ans %= mod;
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> k;
solve(n);//n为k倍数的情况
solve(n-1);//n-1为k倍数的情况
ans += (n+k-1);
cout << ans % mod << endl;
return 0;
}