A-必做题11-1
蒜头君从现在开始工作,年薪 NN 万。他希望在蒜厂附近买一套 6060 平米的房子,现在价格是 200200 万。假设房子价格以每年百分之 KK 增长,并且蒜头君未来年薪不变,且不吃不喝,不用交税,每年所得 NN 万全都积攒起来,问第几年能够买下这套房子?(第一年年薪 NN 万,房价 200200 万)
输入格式
一行,包含两个正整数 N(10 \le N \le 50)N(10≤N≤50),K(1 \le K \le 20)K(1≤K≤20),中间用单个空格隔开。
输出格式
如果在第 2020 年或者之前就能买下这套房子,则输出一个整数 MM,表示最早需要在第 MM 年能买下;否则输出"Impossible"。
输出时每行末尾的多余空格,不影响答案正确性
样例
输入
50 10
输出
8
解题思路
房价为 200 * pow( 1+ K/100 , i-1 )
工资为 i * N
比较2个的大小即可
代码实现
#include<iostream>
#include<cmath>
using namespace std;
float N;
float K;
int main()
{
cin>>N>>K;
float a;
float b;
int flag=0;
float i;
for(i=1;i<=20;i++)
{
a = i * N;
b = 200 * pow((1+K/100),i-1);
if(a>=b) {
cout<<i<<endl;
flag++;
return 0;
}
}
if(flag==0)
{
cout<<"Impossible"<<endl;
return 0;
}
return 0;
}
B - 必做题 11-2

样例输入
4
0 0 0 0
0 0 0 0
0 1 0 0
0 0 0 0
0 0 0 0
0 1 0 0
0 0 0 0
0 0 0 0
样例输出
1
解题思路
顺时针90度 ---- [ i , j ] ----> [ j , n+1-i]
顺时针180度 -------[ i , j ] -----> [ n+1-i , n+1-j ]
顺时针270度 ------- [ i , j] -------> [ n+1-j ,i]
把当前矩阵和目标矩阵进行比较就可以了
代码
#include<iostream>
using namespace std;
bool a[25][25];
bool b[25][25];
int n;
bool _1()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(a[i][j]!=b[i][j]) return 0;
}
}
return 1;
}
bool _2()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(a[i][j]!=b[j][n+1-i]) return 0;
}
}
return 1;
}
bool _3()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(a[i][j]!=b[n+1-i][n+1-j]) return 0;
}
}
return 1;
}
bool _4()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(a[i][j]!=b[n+1-j][i]) return 0;
}
}
return 1;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>b[i][j];
}
}
if(_1()) {cout<<0<<endl;return 0;}
if(_2()){cout<<1<<endl;return 0;}
if(_3()){cout<<2<<endl;return 0;}
if(_4()){cout<<3<<endl;return 0;}
cout<<-1<<endl;
return 0;
}
C - 必做题11-3

样例
NS BFW, JAJSYX TK NRUTWYFSHJ FWJ YMJ WJXZQY TK YWNANFQ HFZXJX
IN WAR, EVENTS OF IMPORTANCE ARE THE RESULT OF TRIVIAL CAUSES
解题思路
把一行字符串全部读取到string里面,
用getline(cin,str) ,
可以连同空格一起读入,如果只是用cin的话,遇到空格和回车就会停止
用 str[i] = (str[i]-'A'+26-5)%26+'A'
来将该字符退回到前5个
代码
#include<iostream>
#include<string>
using namespace std;
string str;
bool jud(int i)
{
char c[] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
for(int j=0;j<26;j++)
{
if(c[j]==str[i]) return 0;
}
return 1;
}
int main()
{
getline(cin,str);
for(int i=0;i<str.size();i++)
{
if(jud(i)) continue;
else
{
str[i] = (str[i]-'A'+26-5)%26+'A' ;
}
}
cout<<str<<endl;
return 0;
}
D - 必做题11-4

Examples
Input
7
2 2 2 1 1 2 2
Output
4
Input
6
1 2 1 2 1 2
Output
2
Input
9
2 2 1 1 1 2 2 2 2
Output
6
解题思路
1.想办法把一段相同的个数个记录下来,例如11112222,记为4 4
2.然后把能够拿走的个数给记录下来,例如 11122221111,很显然为 3 4
3.比较2中所有记录的大小,取出最大的
代码实现
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 1e5+10;
int a[N];
vector<int> b;
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
int sum1=0;
int flag=a[0];
a[n] = -1;
for(int i=0;i<=n;i++) //第一步
{
if(flag==a[i])
{
sum1++;
flag=a[i];
}
else
{
b.push_back(sum1);
sum1=1;
flag = a[i];
}
}
int ai=0;
for(int i=0;i<b.size()-1;i++) //第二步
{
if(b[i]>b[i+1])
{
a[ai++] = b[i+1];
}
else
{
a[ai++] = b[i];
}
}
sort(a,a+ai); //第三步
cout<<a[ai-1]*2;
return 0;
}
E - 选做题11-1 东东与 ATM ( 多重背包+二进制拆分 == 0 1 背包 )

Sample Input
735 3 4 125 6 5 3 350
633 4 500 30 6 100 1 5 0 1
735 0
0 3 10 100 10 50 10 10
Sample Output
735
630
0
0

解题思路
1.多重背包 (一开始我写多重背包的代码,但是超时了)
代码
#include<iostream>
using namespace std;
const int N=100005;
struct W{
int _nk_ , _dk_ ; //_dk_ -- 面额 _nk_ 数量
};
W w[15];
int f[15][N];
int main()
{
int cash,n,nk,dk; //cash总量 n面额数量 nk是dk的数量 dk是面额
while(cin>>cash>>n){
for(int i=1;i<=n;i++)
{
cin>>w[i]._nk_>>w[i]._dk_;
// cout<<w[i]._dk_<<" "<<w[i]._nk_<<endl;
}
//initial
for(int i=0;i<=N;i++)
f[0][i] = 0;
//多重背包
for(int i=1;i<=n;i++)
{
for(int j=0;j<=cash;j++)
{
f[i][j] = f[i-1][j];
// cout<<"1.fij="<<f[i][j]<<endl;
for(int k=1;k<=w[i]._nk_;k++)
{
if(j - k * w[i]._dk_ >= 0){
f[i][j] = max(f[i][j] ,f[i-1][j-k*w[i]._dk_]+k*w[i]._dk_);
// cout<<"2.f["<<i<<","<<j<<"]="<<f[i][j]<<endl;
}
}
}
}
int m=f[n][cash];
cout<<m<<endl;
}
return 0;
}
2.二进制拆分后 ,还要转换成 01背包进行求解,不然可能会超空间
3.二进制拆分的思路:
例子: 111111 拆成 1 + 10 + 100 + 1000 + 100000.......
如果不能刚好拆完,则最后剩下的那个数也算为拆分的一部分
为什么要二进制拆分?
通过二进制拆分,可以转换成01背包
例如 111 = 1 + 10 + 100 ,本来是要在 111里面进行一个for循环遍历的(多重背包)
但是如果把他拆分了,就可以转换成 01 ,选或者不选,如果1 10 100全部都选了,加起来就是111 ,相当于在多重背包里面把这种物体选完了。
多重背包的那部分复杂度降为了log
但是还是不行,因为如果 f【】【】是二维的,是会超空间的
所以要用一维数组实现
代码
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100005;
int cash,n,nk,dk; //cash总量 n面额数量 nk是dk的数量 dk是面额
struct W{
int _nk_ , _dk_ ; //_dk_ -- 面额 _nk_ 数量
};
W w[15];
int ww[N];
int index;
int f[N];
void acc() //二进制拆分
{
index=0;
for(int i=1 ; i<= n ;i++) //第i种面额
{
int c = w[i]._nk_;
for(int j=1;j<= c ;j<<=1)
{
index++;
ww[index] = j*w[i]._dk_;
c -= j;
}
if(c > 0)
{
index++;
ww[index] = c*w[i]._dk_;
}
}
}
void ini() //初始化
{
memset(ww,0,sizeof(ww));
for(int i=0;i<15;i++)
{
w[i]._dk_=0;
w[i]._nk_=0;
}
memset(f,0,sizeof(f));
}
int main()
{
while(cin>>cash>>n){
ini();
for(int i=1;i<=n;i++)
{
cin>>w[i]._nk_>>w[i]._dk_;
}
acc();
//01 背包
for(int i=1; i<=index; i++)
{
for(int j=cash;j>=ww[i];j--)
{
f[j] = max(f[j] ,f[j-ww[i]]+ww[i]);
}
}
cout<<f[cash]<<endl;
}
return 0;
}
F - 选做题11-2 东东开车了

Sample Input
5 3 1 3 4
10 4 9 8 4 2
20 4 10 5 7 4
90 8 10 23 1 2 3 4 5 7
45 8 4 10 44 43 12 9 8 2
Sample Output
1 4 sum:5
8 2 sum:10
10 5 4 sum:19
10 23 1 2 3 4 5 7 sum:55
4 10 12 9 8 2 sum:45
解题思路
01背包求解 (需要用到的是二维的数组)
倒推过程
详情看代码注释
代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
int N,M;
int m[25];
int f[25][10005];
int a[25];
void ini() //初始化
{
memset(a,0,sizeof(a));
memset(f,0,sizeof(f));
memset(m,0,sizeof(m));
}
int main()
{
while(cin>>N>>M)
{
ini();
for(int i=1;i<=M;i++)
cin>>m[i];
//01背包
for(int i=1;i<=M;i++)
{
for(int j=0;j<=N;j++)
{
f[i][j] = f[i-1][j];
if(j>=m[i])
{
f[i][j] = max( f[i][j] , f[i-1][j-m[i]] + m[i] );
}
}
}
//倒推
int b = N;
for(int i=M;i>=1;i--)
{
if(f[i][b]>f[i-1][b]) //如果(f[i][b]>f[i-1][b])
{ //则代表该状态选择了a【i】
a[i] = 1;
b -=m[i];
}
}
for(int i=1;i<=M;i++)
{
if(a[i]==1) //如果为1 ,则该唱片被选择
{
cout<<m[i]<<" ";
}
}
cout<<"sum:"<<f[M][N]<<endl;
}
return 0;
}
本文精选了多项算法竞赛题目,包括房价预测与购房策略、矩阵旋转对比、凯撒密码解密、连续数字最大配对、ATM取款最优策略及唱片收集问题。深入解析了动态规划、数学模型、字符串处理、数据结构等核心算法,提供了详细的代码实现。
275

被折叠的 条评论
为什么被折叠?



