P1255 数楼梯
思路
斐波那契数列+高精度加
实现
int n,f[5010][5010],len;
void jiafa(int k)//高精加法
{
for(int i=1; i<=len; i++)//两数相加
f[k][i]=f[k-1][i]+f[k-2][i];
for(int i=1; i<=len; i++)//进位
if(f[k][i]>=10)
{
f[k][i+1]+=f[k][i]/10;
f[k][i]%=10;
if(f[k][len+1]>0)len++;
}
}
int main()
{
cin>>n;
len=1;
f[1][1]=1;//预处理
f[2][1]=2;//预处理
for(int i=3; i<=n; i++)//开始计算
jiafa(i);
for(int i=len; i>=1; i--)//输出
cout<<f[n][i];
return 0;
}
P1002 [NOIP2002 普及组] 过河卒
思路
本题中马的位置是固定不动的,用一个全0数组来记录整个地图,将马的控制点全部标记为1也就是不能走的。用一个简单的动态规划(可以叫做递推(?))即可
实现
#include <bits/stdc++.h>
using namespace std;
long long a,b,n,m,x[23][23],ma[23][23];
void work(long long x,long long y){
ma[x][y]=1;
ma[x-1][y-2]=1;
ma[x-2][y-1]=1;
ma[x-2][y+1]=1;
ma[x-1][y+2]=1;
ma[x+1][y-2]=1;
ma[x+2][y-1]=1;
ma[x+2][y+1]=1;
ma[x+1][y+2]=1;
}
int main(){
scanf("%lld %lld %lld %lld",&n,&m,&a,&b);
a++;
b++;
n++;
m++;
work(a,b);
x[1][1]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(i==1&&j==1)continue;
if(ma[i][j]==0)x[i][j]=x[i-1][j]+x[i][j-1];
}
}
printf("%lld",x[n][m]);
return 0;
}
P1044 [NOIP2003 普及组] 栈
思路
比较容易卡住的一步是明确dp数组的定义:
f
[
i
]
[
j
]
f[i][j]
f[i][j],i表示栈内数字的个数,j表示未进栈数字的个数,f记录当前状态下有几种情况。
状态转移有两种情况,一种是i==0,栈内没有东西,那么
f
[
i
]
[
j
]
f[i][j]
f[i][j] =
f
[
i
+
1
]
[
j
−
1
]
f[i+1][j-1]
f[i+1][j−1]也就是该状态只能由某一个状态pop一个元素得到。i>0时,
f
[
i
]
[
j
]
f[i][j]
f[i][j] =
f
[
i
+
1
]
[
j
−
1
]
+
f
[
i
−
1
]
[
j
]
f[i+1][j-1]+f[i-1][j]
f[i+1][j−1]+f[i−1][j],该状态可以由某一状态pop一个元素或者某一状态push一个元素得到。
实现
int f[20][20];
int n;
int main()
{
memset(f,0,sizeof(f));
scanf("%d",&n);
for(int i=0;i<=n;i++)
f[i][0]=1;
for(int j=1;j<=n;j++)
for(int i=0;i<=n;i++)
//我们要推f[0][n],所以i要从零开始跑
{
if(i>=1)
f[i][j]=f[i-1][j]+f[i+1][j-1];
if(i==0)//栈内没有东西
f[i][j]=f[i+1][j-1];
}
printf("%d",f[0][n]);
return 0;
}
P1028 [NOIP2001 普及组] 数的计算
思路
一个简单的dp~ 注意dp[i]++
实现
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[1010];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
for(int cur = 1;cur<=i/2;cur++)
{
dp[i] +=dp[cur];
}
dp[i]++; //记得加上自身
}
cout<<dp[n];
return 0;
}
P1928 外星密码
思路
参考了非常好的题解~注意oj里应该是ctrl z结束而不是换行符
实现
string read()
{
int n;
string s="",s1;
char c;
while (cin>>c)//一直读入字符,直到Ctrl+z //cin会忽略换行符 所以这里写!='\n'之类的没有意义
{
if (c=='[')
{
cin>>n;//读入D
s1=read();//读入X
while (n--) s+=s1;//重复D次X
//注:上面不能写成while (n--) s+=read();
}
else
{
if (c==']') return s;//返回X
else s+=c;//如果不是'['和']',那就是X的一个字符,所以加进X
}
}
}
int main()
{
cout<<read();
return 0;
}
P1164 小A点菜
思路
明确dp数组的定义:
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示前i道菜花了j元,f记录当前状态下有几种情况。
状态转移有三种情况,剩的钱不够买这道菜,那就只能不买(废话)
f
[
i
]
[
j
]
f[i][j]
f[i][j] =
f
[
i
−
1
]
[
j
]
f[i-1][j]
f[i−1][j]。剩的钱刚好够买这道菜,那就要么不买,要么买这道菜然后结束。剩的钱比这道菜的价格多,那就要么不买要么买。(废话)
实现
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
vector<int> a(n+1);
vector<vector<int> > f(n+1,vector<int>(m+1,0));
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(j==a[i]) f[i][j] = f[i-1][j]+1;
else if(j<a[i]) f[i][j] = f[i-1][j];
else if(j>a[i]) f[i][j] = f[i-1][j]+f[i-1][j-a[i]];
}
}
cout<<f[n][m];
return 0;
}
P1990 覆盖墙壁
思路
待补充-
实现
#include<iostream>
using namespace std;
const int maxn=1000002;
const int mod=10000;
int f[maxn],g[maxn];
int main()
{
int n;
cin>>n;
f[0]=1; //g[0]=0
f[1]=g[1]=1;
for(int i=2;i<=n;i++)
{
f[i]=((f[i-1]+f[i-2])%mod+2*g[i-2]%mod)%mod;
g[i]=(g[i-1]+f[i-1])%mod;
}
cout<<f[n];
return 0;
}
欢迎指正-