问题 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<bits/stdc++.h>
using namespace std;
struct cmp
{
bool operator()(int& a,int& b)
{
return a>b;
}
};
int main()
{
priority_queue<int,vector<int>,cmp> queue;
int n,L,tmp,sum=0, a, b;
cin>>n>>L;
for(int i=0;i<n;i++)
{
cin>>tmp;
queue.push(tmp);
}
while(queue.size()>1)
{
a=queue.top();
queue.pop();
b=queue.top();
queue.pop();
sum=sum+a+b;
queue.push(a+b);
}
cout<<sum<<endl;
}
问题 B: algorithm-最长公共子序列
题目描述
一个字符串A的子串被定义成从A中顺次选出若干个字符构成的串。如A=“cdaad" ,顺次选1,3,5个字符就构成子串" cad" ,现给定两个字符串,求它们的最长共公子串。
输入
第一行两个字符串用空格分开。两个串的长度均小于2000 。
输出
最长子串的长度。
样例输入 Copy)
abccd aecd
样例输出 Copy)
3
#include <bits/stdc++.h>
#include<string>
using namespace std;
char x[2010], y[2010];
int m, n;
int c[2021][2010]={0};
void Lcs_Length()
{
for (int i=1; i<=m; i++){
for (int j=1; j<=n; j++)
{
if (x[i-1]==y[j-1])
{
c[i][j] = c[i-1][j-1] + 1;
}
else if (c[i-1][j] >= c[i][j-1])
{
c[i][j] = c[i-1][j];
}
else
{
c[i][j] = c[i][j-1];
}
}
}
cout<<c[m][n];
}
int main(){
cin>>x>>y;
m = strlen(x);
n = strlen(y);
Lcs_Length();
return 0;
}
问题 C: algorithm-矩阵连乘
题目描述
给定n个矩阵{A1,A2,...,An},及m个矩阵连乘的表达式,判断每个矩阵连乘表达式是否满足矩阵乘法法则,如果满足,则计算矩阵的最小连乘次数,如果不满足输出“MengMengDa“。
输入
输入数据由多组数据组成(不超过10组样例)。每组数据格式如下: 第一行是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 <bits/stdc++.h>
#include<string>
using namespace std;
struct node{
char name;
int r=0;
int c=0;
}a[30];
int convert(char x, int n) {
int i;
for( i=0; i<n; i++) if(a[i].name == x) break;
return i;
}
long int MatrixCharin(int *p, int n,long int m[][101])
{
for(int i=0;i<=n;i++) m[i][i]=0;
for(int r=2; r<=n; r++) // r个矩阵相乘
for(int i=1; i<=n-r+1; i++)
{
int j = i+r-1; // 本循环的最后一个矩阵
m[i][j] = m[i][i] + m[i+1][j] + p[i-1]*p[i]*p[j]; // 假设最优划分位于i处
for(int k= i+1; k<j; k++) // 变化最优分割的位置, 逐一测试
{
long int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
if(t < m[i][j] ) m[i][j] = t; // 如果更优替换原位置
}
}
return m[1][n];
}
int main() {
int m, n;
char str[3][101]; // 输入的矩阵字符串
long int x[101][101];
int p[3][101];
int flag[3];
while(cin>>n>>m){
memset(str, 0, sizeof(' '));
for(int i=0; i < n; i++) cin>>a[i].name>>a[i].r>>a[i].c;
for(int i=0; i< m ; i++)
{
cin>>str[i];
flag[i]=0;
for(int k=0; k< strlen(str[i]); k++)
{
if(k==0){
p[i][k] = a[convert(str[i][k], n)].r;
p[i][k+1] = a[convert(str[i][k], n)].c;
}
else {
if(p[i][k] == a[convert(str[i][k], n)].r){
p[i][k+1] = a[convert(str[i][k], n)].c;
}
else{
flag[i]=1;
}
}
}
}
for(int i=0; i<m ; i++)
{
if(flag[i] == 1){
cout<<"MengMengDa"<<endl;
}
else {
long int result = MatrixCharin(p[i], strlen(str[i]), x);
cout<<result<<endl;
}
}
}
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
#include <bits/stdc++.h>
using namespace std;
int dp[301][301]; // 最小代价
int MatrixCharin(int *a, int n){
memset(dp, 0, sizeof(dp));
for(int r=2;r<=n;r++){ // 共几个沙堆相加
for(int i=1;i<=n-r+1;i++){
int j=i+r-1; // 本循环的最后一个沙堆
dp[i][j] = dp[i][i] + dp[i+1][j]+ a[j]-a[i-1];
for(int k=i+1;k<j;k++){
int t = dp[i][k] + dp[k+1][j] + a[j]-a[i-1];
if(t < dp[i][j]){
dp[i][j] = t;
}
}
}
}
return dp[1][n];
}
int main(){
int n;
cin>>n;
int *a = new int[n];
a[0]=0;
for(int i=1;i<=n;i++) {
cin>>a[i];
a[i]= a[i]+a[i-1];
}
cout<<MatrixCharin(a, n);
delete[] a;
return 0;
}
问题 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<bits/stdc++.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int t = 1000000;
int s[t];
// 产生随机整数
int random(int begin,int end)
{
srand((unsigned)time(NULL));
return rand()%(end - begin + 1) + begin;
}
// 将小于基点的放在基点左侧,大于的放在右侧
int Partition(int a[], int p, int r){
int i=p;
int j=r+1;
int x = a[p];
while(1){
while(a[++i]<x && i<r);
while(a[--j] > x);
if(i>=j) break;
swap(a[i], a[j]);
}
a[p] = a[j];
a[j] = x;
return j; // 返回排序后基点序号
}
// 随机选择基准点
int RandomizedPartition(int a[], int p, int r){
int i = random(p, r);
swap(a[i], a[p]);
return Partition(a, p, r);
}
int RandomizedSelect(int a[], int p, int r, int k){
if(p==r) return a[p];
int i= RandomizedPartition(a, p, r);
int j = i - p + 1; // 在基点左侧的数的个数
if(k <= j) return RandomizedSelect(a, p, i, k); // 在基点的左侧找
else return RandomizedSelect(a, i+1, r, k-j); // 在基点右侧的 找第k-j小
}
int main(){
int n,k,sum=0;
cin>>n>>k;
for(int i=0; i<n; i++) cin>>s[i];
sum = RandomizedSelect(s, 0, n-1, k);
cout<<sum;
return 0;
}
问题 F: algorithm-快速幂
题目描述
输入
多组测试样例,最多50组。每组测试样例给定一个整数x(1<=x<=25000)
输出
对每个样例,输出一行,代表f(x)对100000007取余的结果。
样例输入 Copy)
3 4 5
样例输出 Copy)
33 289 3414
#include<bits/stdc++.h>
using namespace std;
const long long tmp = 100000007; // 对它取余
int fastPower(long long base, long long power) {
long long result = 1;
while (power > 0) {
if (power & 1) {//此处等价于if(power%2==1) 二进制最后一位与1相与
result = result * base % tmp;
}
power >>= 1;//此处等价于power=power/2 ,对二进制右移一位
base = (base * base) % tmp;
}
return result;
}
int main(){
long long x;
while(cin>>x){
long long sum = 0;
for(long long i=1;i<=x;i++){
sum = sum + fastPower(i, i);
sum=sum%tmp;
}
cout<<sum + 1<<endl;
}
return 0;
}
问题 G: algorithm-排列问题
题目描述
输入一个可能含有重复字符的字符串,打印出该字符串中所有字符的全排列。
输入
单组测试数据,输入数据是一个长度不超过10个字符的字符串,以逗号结尾。
输出
打印出该字符串中所有字符的全排列。以字典序顺序输出,用空格分隔。
样例输入 Copy)
abc,
样例输出 Copy)
abc acb bac bca cab cba
#include<iostream>
#include<string.h>
using namespace std;
// 交换函数
void Swap(char& a, char& b){
char c = a;
a = b;
b = c;
}
void Sort(char *arr,int begin,int end){
int i,j;
for(i=begin;i<=end;i++){
for(j=i+1;j<=end;j++){
if(arr[i]>arr[j]){
Swap(arr[i],arr[j]);
}
}
}
}
// 全排列 递归
void Rank(char* b, int start, int end){
if (start == end){
for (int i = 0; i <= end; i++) cout<<b[i];
cout<<" ";
}
else{
// 固定首字符,对剩下的字符进行全排列,然后回归,切换首字符 ,直到从start到end的字符全被切换
for (int i = start; i <= end; i ++){
Swap(b[i], b[start]);
Sort(b, start + 1, end); // 对交换后所有元素进行排序
Rank(b, start + 1, end); // 排列
Sort(b, start + 1, end); // 还原排列之前的顺序
}
}
}
int main()
{
char a[10];
cin>>a;
int n = strlen(a);
// 以逗号结尾 ,传n-1个值
Sort(a, 0, n-2);
Rank(a, 0, n-2);
return 0;
}
问题 H: algorithm-进制转换
题目描述
输入一个十进制正整数,然后输出它所对应的八进制数。
输入
输入一个十进制正整数n(1≤n≤106) 。
输出
输出n对应的八进制数,输出在一行。
样例输入 Copy)
10
样例输出 Copy)
12
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
int x,y;
cin>>x;
vector <int> z;
int i=0;
while(x){
y = x % 8;
z.push_back( y );
x = x / 8;
i++;
if(x<8){
z.push_back(x);
x = 0;
}
}
reverse(z.begin(), z.end()); // 对容器z中的元素倒序
for(int i = 0; i < z.size(); i++)
cout<<z[i];
return 0;
}
问题 I: algorithm-奶牛的聚会
题目描述
农历新年马上就要到了,奶牛们计划举办一次聚会庆祝新年的到来。但是,奶牛们并不喜欢走太远的路,这会给他们的聚会带来消极情绪,当一头奶牛的消极指数为Wi,他参加聚会所需行走的距离为si,那么他就会给聚会带来Si3*Wi的消极情绪。所有奶牛所在位置都在一条直线上,已知所有奶牛的坐标和消极指数,求如何确定聚会地点,使得所有奶牛给聚会带来的消极情绪之和最小,输出消极情绪之和的最小值。
输入
第一行包含一个整数 Ca(Ca<=20) ,表示有 Ca 组测试数据。
对于每组测试数据:第一行包含一个整数n(1<=n<=50000) ,表示奶牛的数量。接下来 n 行每行包含两个浮点数Si和wi (-106<=Si<=106, 0<Wi<15)。
输出
对于每组测试数据,输出 "Case #c: ans" ,其中c表示测试数据编号,ans表示消极情绪之和的最小值,结果四舍五入为一个整数。
样例输入 Copy)
1 5 0.9 2 1.4 4 3.1 1 6.2 1 8.3 2
样例输出 Copy)
Case #1: 300
#include <iostream>
#include<cmath>
typedef long long ll;
using namespace std;
double *s = NULL;
double *w = NULL;
int x;
// 定义的函数计算情绪之和
double F(double t){
double sum = 0;
for(int i=0;i<x;i++){
sum += pow(abs(s[i]-t), 3)*w[i];
}
return sum;
}
int main(){
int n, k;
cin>>n; // n组测试数据
k = n;
while(k--){
cin>>x; // x个数据
s = new double[x];
w = new double[x];
double l = 1000000, r = -1000000;
for(int i=0;i<x;i++){
cin>>s[i]>>w[i];
r = max(s[i], r); // r 是坐标轴上的最小值
l = min(s[i], l); // l 是坐标轴上的最大值
}
while(r-l>0.000001){
double x1 = l + (r-l)/3; // x1取 [l, r]区间的1/3 点
double x2 = r - (r-l)/3; // x2取 [l, r]区间的2/3 点
if(F(x1) > F(x2)) l = x1; // 若x1点的情绪之和较大, 则x1替换l
else r= x2;
}
cout<<"Case #"<<n-k<<": "<< ll(F(l) + 0.5)<<endl;
}
delete []s;
delete []w;
return 0;
}
问题 J: algorithm-跳台阶
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
输入
多组测试样例。每组测试样例包含一个整数n。(1<=n<=100)
输出
每组测试样例输出一行,表示青蛙跳上n级台阶的跳法数量.
所得到的结果模1000000007
样例输入 Copy)
3 4
样例输出 Copy)
3 5
#include <iostream>
using namespace std;
int res[100];
int tmp = 1000000007;
int Max = 2;
int dp(int n){
if(n <= Max){
return res[n];
}
else{
res[n] = (dp(n-1) + dp(n-2))%tmp; // (a+b)%c = (a%c + b%c)%c
Max = n;
}
return res[n];
}
int main(){
int n;
res[0] = 0;
res[1] = 1;
res[2] = 2;
while(cin>>n){
cout<<dp(n)<<endl;
}
return 0;
}