用于辅助备战第十届
A.完善新谷密
题目图片都没了,还做什么
B.爬楼梯(*1100)
考查:动态规划
分析:用数组dp[N]表示薯片到达第i个台阶上时,已经丢失了dp[i]个糖果。假设薯片现在正在第0个阶梯上,那么初始状态就是dp[0]=0。如果薯片在第i个阶梯上,用j来表示薯片上一次的步数,那么i一定大于等于j,上一次丢失的糖果就是dp[i-j],加上这一次丢的糖果a[i],现在丢失的糖果就是dp[i-j]+a[i]。因为薯片最多一次上m个阶梯,因此对j循环时从1~m遍历一遍并持续更新dp[i]的值,状态转移方程就是dp[i]=min(dp[i],dp[i-j]+a[i])。
Code:
#include<bits/stdc++.h>
using namespace std;
int a[1010],dp[1010];
int main()
{
int n,m;
while(cin>>n>>m)
{
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) dp[i]=1e9;
dp[0]=0,a[0]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(i>=j) dp[i]=min(dp[i],dp[i-j]+a[i]);
cout<<dp[n]<<'\n';
}
}
C.吃薯条(*1000)
考查:思维
分析:最优的策略是,我们可以先将所有的薯条分成两半部分,并将右半部分尽可能的吃光,然后对各部分再进行相同的操作(类似于分治?)。假设有6个薯条[1,2,3,4,5,6],我们将它们分成两部分[1,2,3|4,5,6],然后去吃右半部分[1,2,3|0,1,2]。接下来对两部分重复上述操作:
[1,2|3|0,1|2]——>[1,2|1|0,1|0]——>[1|2|1|0|1|0]——>[1|1|1|0|0|0]——>[0|0|0|0|0|0]
答案为f[n]=f[(n+1)/2]+1
Code:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(cin>>n)
{
int ans=0;
while(n)
{
ans++;
n/=2;
}
cout<<ans<<'\n';
}
}
D.拿糖果(*1000)
考查:思维
分析:我们对第1~n-1个糖果进行遍历(不可能拿最后一个),因为手上拿的糖果价值已经既定了,因此我们要保证后面拿的糖果价值尽可能小,即要求出i∈[2,n],a[i]~a[n]之间的最小值。这里逆序处理会比较方便,用num[N]记录区间中的最小值,然后倒序遍历。求出num数组后,与代表价值的数组求差然后选出最大值即可。注意最大值初始化时要尽可能小,答案可能为负数。
Code:
#include<bits/stdc++.h>
using namespace std;
int a[100010],num[100010];
int main()
{
int n;
while(cin>>n)
{
for(int i=1;i<=n;i++) cin>>a[i];
num[n]=a[n];
int ans=a[n-1]-a[n];
for(int i=n-1;i;i--)
{
num[i]=min(a[i],num[i+1]);
ans=max(ans,a[i]-num[i+1]);
}
cout<<ans<<'\n';
}
}
E.蔡老板的会议(*1700)
考查:最短路算法
分析:说到最短路,那么第一个想到dijkstra算法,但是此算法更适用于单源最短路,即更适合从蔡老板的办公室回去这个子问题。而大家到蔡老板的办公室是多源最短路,更适合用Floyd算法,不过我们依然可以选择dijkstra算法。既然大家一个一个去找蔡老板很麻烦,为什么不反过来让蔡老板去一个一个找他们呢?那么我们就可以进行反向建边,将多源最短路转化成单源最短路,然后进行两次找最短路,将结果相加取最大就是答案(洛谷的图论题集很多都是反向建边,可以康康)。注意本题是多组输入,只是输入描述没写!
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int g[N][N],G[N][N],dist[N],dis[N];
bool st[N];
int n,m,x;
void dijkstra(int u)
{
memset(dist,0x3f,sizeof(dist));
memset(st,false,sizeof(st));
dist[u]=0;
for(int i=1;i<=n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
if(!st[j]&&(t==-1||dist[t]>dist[j])) t=j;
st[t]=true;
for(int j=1;j<=n;j++)
dist[j]=min(dist[j],dist[t]+g[t][j]);
}
}
void dijkstra2(int u)
{
memset(dis,0x3f,sizeof(dis));
memset(st,false,sizeof(st));
dis[u]=0;
for(int i=1;i<=n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
if(!st[j]&&(t==-1||dis[t]>dis[j])) t=j;
st[t]=true;
for(int j=1;j<=n;j++)
dis[j]=min(dis[j],dis[t]+G[t][j]);
}
}
int main()
{
while(cin>>n>>m>>x)
{
memset(g,0x3f,sizeof(g));
memset(G,0x3f,sizeof(G));
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
g[a][b]=min(g[a][b],c);
G[b][a]=min(G[b][a],c);
}
int maxx=0;
dijkstra(x);
dijkstra2(x);
for(int i=1;i<=n;i++) maxx=max(maxx,dist[i]+dis[i]);
cout<<maxx<<'\n';
}
}
F.一个简单的问题(*800)
我想这题没什么好说的
Code:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(cin>>n)
{
for(int i=n-1;i>=0;i--)
{
for(int j=1;j<=i;j++) cout<<' ';
char c='A';
for(int j=1;j<=n-i;j++)
{
cout<<c;
c++;
}
c--;
for(int j=1;j<n-i;j++)
{
c--;
cout<<c;
}
cout<<'\n';
}
}
}
G.粉丝与汉诺塔(*1000)
考查:思维,递推
分析:以普遍情况为例,设A上有n个盘子,则需要f[n]步,转移步骤为:
(1)将A上垫底的盘子上面的n-1个盘子通过B移动到C,即f[n-1]步
(2)将A上剩下的最大一个盘子移动到B,共1步
(3)将C上的n-1个盘子通过B移动到A,共f[n-1]步
(4)将B上的那个最大的盘子移动到C,共1步
(5)将A上的n-1个盘子通过B移动到C,共f[n-1]步
即f[n]=3*f[n-1]+2,n=1时,f[1]=2
Code:
#include<bits/stdc++.h>
using namespace std;
int f[20],n;
int main()
{
f[1]=2;
for(int i=2;i<=18;i++) f[i]=3*f[i-1]+2;
while(cin>>n) cout<<f[n]<<'\n';
}
H.粉丝与分割平面(*1500)
考查:思维,递推
结论题
Code:
#include<iostream>
#include<math.h>
using namespace std;
int main()
{
int t,n,m;
cin>>t;
while(t--)
{
cin>>n>>m;
long long x=2*n*n-n+1;
long long y=2+m*(m-1);
cout<<x<<" "<<y<<'\n';
}
}