2024/02/26 周一
求阶乘
【参考代码】
#include <iostream>
using namespace std;
#define ll long long
//N!的末尾有k个0, 0其实是由2*5得到的
//为什么说直接算5就行?
//以10!为例:2,4,6,8,10都可以提供2,5,10可以提供5,5的数量是比2少的
ll numberOfzeros(ll number)
{
ll result = 0;
while(number)
{
result += number/5;
number /= 5;
}
return result;
}
int main()
{
// 请在此输入您的代码
ll k;
cin>>k;
ll l = 0, r = 9e18; //1e19不行,爆long long了,所以用9e18次方
while(l<r)
{
ll mid = l+r >> 1;
if(numberOfzeros(mid) >= k)
r = mid;
else
l = mid+1;
}
if(numberOfzeros(r) == k)
cout << r << endl;
else
cout << -1 << endl;
return 0;
}
分巧克力
【参考代码】
暴力75%,罗老师代码更简洁一点
#include <iostream>
using namespace std;
int main() //暴力75%,罗老师代码更简洁一点
{
int n, k;
int h[100000], w[100000];
cin>>n>>k;
for(int i=0;i<n;i++)
{
cin>>h[i]>>w[i];
}
int maxside = 0, chocolate_count = 0;
for(int sidelength=2; sidelength<=1e5; sidelength++) //边长
{
for(int i=0;i<n;i++)
{
chocolate_count += (int)(h[i] / sidelength) * (w[i] / sidelength);
}
if(chocolate_count >= k) //巧克力数量大于孩子数,说明够分
{
maxside = max(maxside, sidelength);
}
else //巧克力数量小于孩子数,就到极限了
break;
chocolate_count = 0;
}
//这里不需要-1,因为我们最大边长不是在循环里面输出的,而是通过比较最大值得出的
if(maxside > 1)
cout << maxside << endl;
else
cout << 1 << endl;
return 0;
}
罗老师的:👍👍👍
#include<bits/stdc++.h>
using namespace std;
int h[100010],w[100010];
int n,k;
bool check(int d){ //检查够不够分
int num=0;
for(int i=0;i<n;i++) num += (h[i]/d)*(w[i]/d);
if(num>=k) return true; //够分
else return false; //不够分
}
int main(){
cin >>n>>k;
for(int i=0;i<n;i++) cin>>h[i]>>w[i];
int d=1; //正方形边长
while(1){
if(check(d)) d++; //边长从1开始,一个个地暴力试
else break;
}
cout << d-1;
return 0;
}
2024/02/27 周二
你不干?有的是帕鲁干!【上周算法赛补题重做】
【思路】
看了题解直播后,恍然大悟,原来是找规律+数学公式。找到规律这题就已经成功一半了。两个连续正奇数的平方之差其实是8的倍数,现在非常后悔自己没多推一个例子。
⚠️需要注意的是,这题由于数据太大,10^18输入输出时需要使用printf, scanf函数节约时间。使用cin, cout容易超时
【参考代码】
lld表示输入的数据类型为long long
#include <iostream>
using namespace std;
int main()
{
//符合平方之差就是8的倍数。设a为正奇数(小的),b=a+2
//x = (b^2)-(a^2)=(b+a)(b-a)
//代入b=a+2得(2a+2)*2=x x=4a+4 x/4=a+1
int t;
cin>>t;
for(int i=0;i<t;i++)
{
long long x;
scanf("%lld", &x);
if(x % 8 == 0 && x != 0)
{
long long Positive_OddNumber1, Positive_OddNumber2;
Positive_OddNumber1 = x / 4 - 1;
Positive_OddNumber2 = x / 4 + 1;
printf("Yes\n");
printf("%lld %lld\n", Positive_OddNumber1, Positive_OddNumber2);
}
else
printf("No\n");
}
return 0;
}
等腰三角形【上周算法赛补题重做】
【思路】
排序是必须的,之后就是使用双指针来寻找是否符合条件:(两边之和大于第三边)。因为题目是等腰三角形,存一条边就可以了,用的时候*2。
回看我的代码,错的离谱,竟然觉得会有红色和蓝色木棍相等的情况。太局限于样例,而没有顾全大局
【参考代码】
可以从小的数开始找,也可以从大的数开始找。
从小的数开始找需要全遍历一遍红色木棍的red数组
int i = 0, j=0, ans = 0;
for( ;i<n; i++) //全遍历red
{
if(red[i] * 2 > blue[j])
{
j++;
ans++;
}
}
从大的数开始找需要全遍历一遍蓝色木棍的blue数组
int a = n - 1; int b = n - 1;
for (; b >= 0; b--) //全遍历blue
{
if (red[a]*2 > blue[b])
a--, ans++;
}
#include <iostream>
#include <algorithm>
using namespace std;
int red[200001], blue[200001];
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>> red[i];
}
for(int i=0;i<n;i++)
{
cin>> blue[i];
}
//不排倒序
sort(red, red+n);
sort(blue, blue+n);
//找blue数组中最小的,先用最小的。
int i = 0, j=0, ans = 0;
for( ;i<n; i++) //全遍历red
{
if(red[i] * 2 > blue[j])
{
j++;
ans++;
}
}
//法二:从red最大开始找, 先用blue最大的
/*
int a = n - 1; int b = n - 1;
for (; b >= 0; b--) //全遍历blue
{
if (red[a]*2 > blue[b])
a--, ans++;
}
*/
cout << ans << endl;
}
2024/02/28 周三
计算方程【上周算法赛补题重做】
【思路】
二分,数学公式
【参考代码】
#include <iostream>
#include <math.h>
using namespace std;
int k, m;
bool check(long long mid)
{
if(sqrt(mid) + floor( log(mid)/log(k) ) > m)
return true;
else
return false;
}
long long solve()
{
long long l = 0, r = 2e8; //因为用二分找,答案在10^4,所以r的最大值10^4 * 10^4
while(l<r)
{
long long mid = l+r >> 1;
if(check(mid))
r = mid;
else
l = mid+1;
}
return l;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>k>>m;
cout << solve() << endl;
}
}
2024/02/29 周四闰日
程序员闰年小知识:4年一闰,100年不闰。400年闰
分巧克力
【参考代码】
100%通过
#include <iostream>
using namespace std;
int n, k;
int h[100000], w[100000];
bool check(int sidelength) //测试二分所求得的边长sidelength
{
int chocolate_count = 0;
for(int i=0; i<n; i++)
chocolate_count += (h[i] / sidelength) * (w[i] / sidelength);
if(chocolate_count >= k)
return true;
else
return false;
}
//二分法把长度为n的有序序列上O(n)的查找时间,优化到了O(logn)。
int main()
{
cin>>n>>k;
for(int i=0;i<n;i++)
cin>>h[i]>>w[i];
int l = 1, r = 100005; //1已经试过了
while(l<r)
{
int mid = (l+r+1) >> 1; //加1防止死循环
//如何判断是否加1
if(check(mid))
l = mid;
else
r = mid - 1;
}
cout << l << endl;
}
2024/3/1 周五
区间覆盖(加强版)
【参考代码】
参考罗老师的代码
#include <iostream>
using namespace std;
#include <algorithm>
#define ll long long
struct section{
ll s;
ll t;
}a[100001];
bool cmp(section data1, section data2)
{
return data1.s < data2.s;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i].s >> a[i].t;
}
sort(a, a+n, cmp);
ll maxlength = -1;
int count = 0;
for(int i=0;i<n;i++)
{
if(a[i].t >= maxlength)
{
count += a[i].t - max(maxlength, a[i].s) + 1;
maxlength = a[i].t + 1;
}
}
cout << count << endl;
}
全排列问题
【参考代码】
#include<bits/stdc++.h>
using namespace std;
int n;
int visit[10]; // 访问标记
int a[10]; //需要做全排列的数组
int result[10]; //当前DFS得到的全排列0~9
void dfs(int step)
{
if (step == n+1) //从1开始计算, n+1
{ //已经对n个数做了全排列,输出全排列
for (int i=1; i<=n; i++)
printf("%5d",result[i]);
printf("\n");
return; //结束
}
for (int i = 1; i <= n; i++) //遍历每个a[i],放进全排列中
{
if (visit[i] == 0)// 数字a[i]不在前面得到的排列中
{
result[step] = a[i]; // 把a[i]放进排列
visit[i] = 1; // 保存现场:a[i]不能在后面继续用
dfs(step + 1); // 继续把后面的数放进排列
visit[i] = 0; // 恢复现场:a[i]重新可以使用
}
}
}
int main() {
cin >> n;
for (int i=1; i<=n; i++)
a[i]=i; //赋值得到n个数
dfs(1); //对a[1]~a[n]做全排列
return 0;
}