牛客动态规划1选做
[NOIP2002]过河卒
进行记忆化搜索,然后强制把马所在的点和控制的点赋值为 0
#include<bits/stdc++.h>
#define int long long
using namespace std;
set<pair<int,int>> st;
int f[25][25];
int calc( int x , int y ){
if( x == 0 && y == 0 ) return f[x][y] = 1;
if( x < 0 || y < 0 ) return 0;
if( st.count( {x,y} ) ) return 0;
if( f[x][y] ) return f[x][y];
return f[x][y] = calc( x - 1 , y ) + calc( x , y - 1 );
}
int32_t main() {
int n , m , s , t;
cin >> n >> m >> s >> t;
st.insert( { s , t } );
st.insert( { s-1 , t-2 } ) ,st.insert( { s-1 , t+2 } );
st.insert( { s+1 , t-2 } ) ,st.insert( { s+1 , t+2 } );
st.insert( { s-2 , t-1 } ) ,st.insert( { s-2 , t+1 } );
st.insert( { s+2 , t-1 } ) ,st.insert( { s+2 , t+1 } );
cout << calc( n , m ) << "\n";
return 0;
}
[NOIP2008]传球游戏
设状态f[i][j]
表示第j
次传球后,球在i
手上的点方案数,则f[i][j]=f[i-1][j-1]+f[i+1][j-1]
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 35;
int f[N][N] , n , m;
int32_t main() {
cin >> n >> m;
f[1][0] = 1;
for( int j = 1 ; j <= m ; j ++ ){
f[1][j] = f[n][j-1] + f[2][j-1];
f[n][j] = f[1][j-1] + f[n-1][j-1];
for( int i = 2 ; i < n ; i ++ )
f[i][j] = f[i-1][j-1] + f[i+1][j-1];
}
cout << f[1][m] << "\n";
return 0;
}
滑雪
记忆化搜索一下,f[x][y]
表示从(x,y)
出发最远可以走多远。
每次只能从相邻且比当前低的点转移过来
#include<bits/stdc++.h>
using namespace std;
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
const int N = 105;
const int dx[] = { 0 , 0 , 1 , -1 } , dy[] = { 1 , -1 , 0 , 0 };
int n , m , h[N][N] , f[N][N] , res = INT_MIN;
int dfs( int x , int y ){
if( x < 1 || y < 1 || x > n || y > m ) return 0;
if( f[x][y] ) return f[x][y];
f[x][y] = 1;
for( int i = 0 , fx , fy ; i < 4 ; i ++ ){
fx = x + dx[i] , fy = y + dy[i];
if( h[x][y] > h[fx][fy] ) f[x][y] = max( f[x][y] , dfs( fx , fy ) + 1 );
}
return f[x][y];
}
int32_t main() {
n = read() , m = read();
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j <= m ; j ++ )
h[i][j] = read();
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j <= m ; j ++ )
res = max( res , dfs( i , j ) );
cout << res;
return 0;
}
方块与收纳盒
https://ac.nowcoder.com/acm/contest/24213/1001
简单的斐波那契额数列
递推版
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
ll f[100];
int32_t main() {
f[0] = f[1] = 1;
for( int i = 2 ; i <= 80 ; i ++ ) f[i] = f[i-1] + f[i-2];
for( int t = read() , x ; t ; t -- )
x = read() , cout << f[x] << "\n";
return 0;
}
递归版
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
ll f[100];
ll calc( int x ){
if( f[x] ) return f[x];
return f[x] = calc( x - 1 ) + calc( x - 2 );
}
int32_t main() {
f[0] = f[1] = 1;
for( int t = read() , x ; t ; t -- )
x = read() , cout << calc(x) << "\n";
return 0;
}
舔狗舔到最后一无所有
https://ac.nowcoder.com/acm/contest/24213/1002
设f[i]
表示前i
天的合法方案。
如果i
天与i-1
天不同,则有两种选择方法
如果i
天与i-1
天相同,就不能与i-2
天相同,与i-2
天不同有两种选择方法
所以f[i] = f[i-1] * 2+ f[i-2]*2
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+5 , mod = 1e9+7;
int f[N];
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
int32_t main() {
f[1] = 3 , f[2] = 9;
for( int i =3 ; i < N ; i ++ )
f[i] = ( f[i-1] + f[i-2] ) % mod * 2 % mod;
for( int t = read() , x ; t ; t -- )
x = read() , cout << f[x] << "\n";
return 0;
}
[NOIP2001]装箱问题
https://ac.nowcoder.com/acm/contest/24213/1017
f[i][j]
表示前i
个物品能否填满空间j
这样就可以得到状态转移方程f[i][j] |= f[i-1][j-v]
然后可以通过倒序枚举的方式优化一维空间
#include <iostream>
#include <string>
#include <vector>
using namespace std;
const int N = 20005;
bool f[N];
int main(){
int v , n; cin >> v >> n;
f[0] = 1;
for( int i = 1 , x ; i <= n ; i ++ ){
cin >> x;
for( int i = v ; i >= x ; i -- )
f[i] |= f[i-x];
}
for( int i = v ; i >= 0 ; i -- )
if( f[i] ) cout << v-i , exit(0);
return 0;
}
可爱の星空
因为合并的时候肯定是尽可能接近的两个数合并才可以使话费尽可能的小,所以为了合成n
必须先合成n/2
,然后处理一下奇数的情况就好
#include<bits/stdc++.h>
#define int long long
using namespace std;
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
map< int , int > g;
int f( int x ) {
if( x == 1 || x == 2 ) return 0;
if( g[x] != 0 ) return g[x];
return g[x] = f(x/2) + f( x/2 + (x&1)) + (x&1);
}
void solve(){
int n = read();
cout << f(n) << "\n";
}
int32_t main() {
for( int t = read() ; t ; t -- )
solve();
return 0;
}
数字三角形
#include<bits/stdc++.h>
using namespace std;
int32_t main() {
int n; cin >> n;
for( int i = 1 , t = 1 ; i <= n ; i ++ ){
for( int j = 1 ; j <= i ; j ++ , t ++ )
cout << setw(4) << t;
cout << "\n";
}
return 0;
}
[NOIP2005]采药
https://ac.nowcoder.com/acm/contest/24213/1018
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, m;
cin >> n >> m;
vector<int> f( n+1 , INT_MIN );
f[0] = 0;
for( int v , w ; m ; m -- ){
cin >> v >> w;
for( int i = n ; i >= v ; i -- )
f[i] = max( f[i] , f[i-v] + w);
}
cout << *max_element(f.begin(), f.end());
return 0;
}
[NOIP2004]合唱队形
求两边最长上升子序列,枚举中间点
#include<bits/stdc++.h>
using namespace std;
#define int long long
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
int32_t main() {
int n = read();
vector<int> a(n+1) , f(n+1 , 1 ) , g(n+1 , 1 );
for( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for( int i = 1 ; i <= n ; i ++ )
for( int j = 1 ; j < i ; j ++ )
if( a[j] < a[i] ) f[i] = max( f[i] , f[j] + 1 );
for( int i = n ; i >= 1 ; i -- )
for( int j = n ; j > i ; j -- )
if( a[j] < a[i] ) g[i] = max( g[i] , g[j] + 1 );
int res = INT_MIN;
for( int i = 1 ; i <= n ; i ++ )
res = max( res , f[i] + g[i] - 1);
cout << n - res << "\n";
return 0;
}