目录
1.123
原题链接:123
题解思路:这题考察的是前缀和+二分,发现每一段的和是从一开始的一段连续区间,我们便可以用等差数列的求和公式进行求和,Sn=na1+n*(n-1)d/2,,于是我们可以预处理出来每段的前缀和当作每个元素,求的时候我们发现要找小于等于所求数的最大的元素的位置
#include<iostream>
#define int long long
using namespace std;
const int N = 1e7 + 10;
int n, m, flag;//flag 代表的是和的总数
int num[N];//存的是前缀和
void init() {
for (int i = 1; i < N; i++) {
int res = i * (i + 1) / 2;
num[i] = res, num[i] += num[i - 1];
flag++;
if (res > 1e12) return;
}
return;
}
//等差数列求和公式
int calc(int k) {
if (k == 0) return 0;
int l = 0, r = flag;
while (l < r) {
int mid = l + r + 1 >> 1;
if (mid * (mid + 1) / 2 <= k) l = mid;
else r = mid - 1;
}
int ans = num[l];//二分查找出小于等于所求数的最大的元素的位置
int v = k - l * (l + 1) / 2;//所求位置的数
ans += v * (v + 1) / 2;//求和
return ans;
}
void solve() {
cin >> n >> m;
cout << calc(m) - calc(n - 1) << endl;
}
signed main() {
init();
int t;
cin >> t;
while (t--) {
solve();
}
}
2.最优包含
原题链接:最优包含
解题思路:这题就是线性dp,类似于最短编辑距离问题,这里要注意f数组要初始化为无穷大便于求最小值,f[i][j]代表的是S串中前i个字符,包含有T串中前j个字符最少需要修改的字符个数,那么就有两种可能前i-1个都和t串的前j-1都相等,或者和t串的前j个都相等,
如果S[i]!=T[j],说明t串是比s串要短的,那么要么是让T[j]和S串的前i-1个的字符一样,要么就是让T【j】的前j-1项相等然后修改最后一位S[i]。
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
char a[N],b[N];
int f[N][N];
int main()
{
scanf("%s",a+1);
scanf("%s",b+1);
int n=strlen(a+1),m=strlen(b+1);
memset(f,0x3f3f3f3f,sizeof f);
f[0][0]=0;
for(int i=1;i<=n;i++)
{
f[i][0]=0;
for(int j=1;j<=m;j++)
{
if(a[i]==b[j])
f[i][j]=min(f[i-1][j],f[i-1][j-1]);
else
f[i][j]=min(f[i-1][j],f[i-1][j-1]+1);
}
}
cout<<f[n][m]<<endl;
return 0;
}
3.混合牛奶
原题链接:
题解思路:这题我用结构体来存储,先按照单价排序,单价小的在前面; 单价一样的就把产量多的放前面,这样来保证费用是最小的
#include <bits/stdc++.h>
using namespace std;
struct cow
{
int a,b;//单价和总量
}c[5010];
bool cmp(cow a,cow b)
{
if(a.a!=b.a)return a.a<b.a;//单价小的排在前面
else return a.b>b.b;//若单价相同则总量大的排在前面
}
int main()
{
int n,m,ans=0;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>c[i].a>>c[i].b;
}
sort(c+1,c+1+m,cmp);
int i=1;
while(n)
{
if(c[i].b!=0)
{
c[i].b--;//产量减1
ans+=c[i].a;//总花费加上单价
n--;//所需求产量减一
}
else
{
i++;//当前农民的牛奶卖完了就换到下一个农民
}
}
cout<<ans<<endl;
return 0;
}