问题 A: algorithm-锯木棒
题目描述
xiaok大佬最近再雇佣工人给他掰木棒。把一根长为L的木棒锯成两段,他需要支付给工人L元钱。xiaok大佬一开始只有长为L的一根木棒,他想把它锯成n段,每段长度分别为L1,L2,...,Ln,问xiaok大佬最少要付给工人多少钱?
输入
第一行两个整数n,L(1<n<103,n<L<109)
第二行n个整数L1,L2,...,Ln(0<Li<L,且保证L1+L2+...+Ln=L)
输出
输出一个整数,表示最小花费
样例输入 Copy
3 21 8 5 8
样例输出 Copy
34
倒着做,贪心
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=1e3+10;
int n,len;
int q[N];
int main(){
priority_queue<int,vector<int>, greater<int> > qu;
scanf("%d%d",&n,&len);
long long cost=0;
for(int i=0;i<n;i++) {
int temp;
scanf("%d",&temp);
qu.push(temp);
}
while(qu.size()>1){
int a=qu.top();
qu.pop();
int b=qu.top();
qu.pop();
int sum=a+b;
cost+=sum;
qu.push(sum);
}
printf("%lld",cost);
}
问题 B: algorithm-最长公共子序列
题目描述
一个字符串A的子串被定义成从A中顺次选出若干个字符构成的串。如A=“cdaad" ,顺次选1,3,5个字符就构成子串" cad" ,现给定两个字符串,求它们的最长共公子串。
输入
第一行两个字符串用空格分开。两个串的长度均小于2000 。
输出
最长子串的长度。
样例输入 Copy
abccd aecd
样例输出 Copy
3
dp板子题
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int N=2010;
char a[N],b[N];
int f[N][N];
int main(){
scanf("%s%s",a+1,b+1);
int n=strlen(a+1);
int m=strlen(b+1);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j]=max(f[i-1][j],f[i][j-1]);
if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
}
}
printf("%d",f[n][m]);
return 0;
}
问题 C: algorithm-矩阵连乘
题目描述
输入
第一行是2个整数n (1≤n≤26)和m(1≤m≤3),表示矩阵的个数。
接下来n行,每行有一个大写字母,表示矩阵的名字,后面有两个整数r和c,分别表示该矩阵的行数和列数,其中1<r, c<100。
第n+1行到第n+m行,每行是一个矩阵连乘的表达式(2<=矩阵个数<=100)。
输出
对于每个矩阵连乘表达式,如果运算不满足矩阵乘法法则的情况(即左矩阵列数与右矩阵的行数不同),则输出“MengMengDa”,否则输出最小矩阵连乘次数。
数据保证结果不超过1e9。
样例输入 Copy
3 2 A 10 100 B 5 50 C 100 5 ACB ABC
样例输出 Copy
7500 MengMengDa
需要注意的是多组样例输入,乘法表达式长度和总矩阵个数不一致
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int N=1050;
typedef pair<int,int> PII;
PII q[N];
long long f[N][N];
int inde[N];
char matrix[N];
int n,m;
bool testValid(string a,int m){
int i=0;
int pre =-1;
while(i<=m){
for(int j=1;j<=n;j++){
if(a[i]==matrix[j]){
if(pre == -1){
pre=q[j].second;
break;
}
if(pre!=q[j].first){
printf("MengMengDa\n");
return false;
}
pre=q[j].second;
}
}
i++;
}
return true;
}
int getMul(int l,int k,int r){
return q[l].first*q[k].second*q[r].second;
}
void dp(string a,int m){
for(int i=0;i<m;i++)
for(int j=1;j<=n;j++)
if(a[i]==matrix[j]) {
inde[i+1]=j;
break;
}
//for(int i=1;i<=m;i++) cout<<index[i]<<" "<<endl;
for(int s=2;s<=m;s++){
for(int l=1;l+s-1<=m;l++){
int r=l+s-1;
f[l][r]=1e8;
for(int k=l;k<r;k++){
f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+getMul(inde[l],inde[k],inde[r]));
//cout<<getMul(index[l],index[r])<<" ";
}
}
}
/* for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) printf("%d ",f[i][j]);
cout<<endl;
}
*/
printf("%d\n",f[1][m]);
}
int main(){
while(scanf("%d %d",&n,&m)==2){
for(int i=1;i<=n;i++){
scanf("%s%d%d",&matrix[i],&q[i].first,&q[i].second);
}
while(m--){
char tmp[110];
scanf("%s",tmp);
if(testValid(tmp,strlen(tmp))) dp(tmp,strlen(tmp));
}
}
return 0;
}
问题 D: algorithm-沙子的质量
题目描述
设有N堆沙子排成一排,其编号为1,2,3,…,N(N< =300)。每堆沙子有一定的数量,可以用一个整数来描述,现在要将N堆沙子合并成为一堆,每次只能合并相邻的两堆,合并的代价为这两堆沙子的数量之和,合并后与这两堆沙子相邻的沙子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同,如有4堆沙子分别为1 3 5 2我们可以先合并1、2堆,代价为4,得到4 5 2又合并1,2堆,代价为9,得到9 2,再合并得到11,总代价为4+9+11=24,如果第二步是先合并2,3堆,则代价为7,得到4 7,最后一次合并代价为11,总代价为4+7+11=22;问题是:找出一种合理的方法,使总的代价最小。输出最小代价。
输入
第一行一个数N表示沙子的堆数N。 第二行N个数,表示每堆沙子的质量。 a[i]< =1000。
输出
合并的最小代价。
样例输入 Copy
4 1 3 5 2
样例输出 Copy
22
dp板子题
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e3;
int q[N],f[N][N];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&q[i]);
q[i]+=q[i-1];
}
for(int s=2;s<=n;s++){
for(int l=1;l+s-1<=n;l++){
int r=l+s-1;
f[l][r]=1e8;
for(int k=l;k<r;k++){
f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+q[r]-q[l-1]);
}
}
}
printf("%d",f[1][n]);
}
问题 E: algorithm-求第k小
题目描述
给定n(1<=n<=1000000)个元素,求第k小数(1<=k<=n)。
输入
一组样例。第一行输入两个整数n和k。第二行输入n个不同的int范围内的数。
输出
输出一行,输出第k小数。
样例输入 Copy
5 2 1 5 3 2 4
样例输出 Copy
2
快排变式
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int n,k,ans;
int q[N];
void quick_sort(int q[],int l,int r,int k){
if(l==r){
ans=q[l];
return ;
}
if(l>r) return ;
int x=q[(l+r)>>1],i=l-1,j=r+1;
while(i<j){
do i++ ; while(q[i]<x);
do j-- ; while(q[j]>x);
if(i<j) swap(q[i],q[j]);
}
if(j-l+1>=k)quick_sort(q,l,j,k);
else quick_sort(q,j+1,r,k-(j-l+1));
}
int main(){
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++) scanf("%d",&q[i]);
quick_sort(q,0,n-1,k);
printf("%d",ans);
}
问题 F: algorithm-快速幂
题目描述
给定x,求f(x)对100000007取余的结果
输入
输出
对每个样例,输出一行,代表f(x)对100000007取余的结果。
样例输入 Copy
3 4 5
样例输出 Copy
33 289 3414
沾点数学知识,二进制优化
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=3e4;
int x,id;
long long q[N];
long long qmi(long long a){
int b=a;
long long ans=1;
while(b){
if(b&1) ans=(ans*a)%100000007;
b=b>>1;
a=(a*a)%100000007;
}
return ans;
}
int quickPower(int x){
if(x<=id) return q[x];
else{
for(int i=id;i<=x;i++){
q[i]=(q[i-1]+qmi(i))%100000007;
}
}
id=x;
return q[x];
}
int main(){
while(scanf("%d",&x)==1){
long long ans=quickPower(x);
printf("%d\n",ans);
}
}