精选竞赛题单(动态规划)

1.状态机

P1353 [USACO08JAN] Running S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<iostream>
#include<map>
#include<cstring>
using namespace std;
#define int long long
#define inf 0x7ffffffffffffff
#define endl "\n"
const int N = 1e6 + 7;
const int mod = 1e9 + 7;
int dp[101100][1010];
int Time[1010][1010];
int a[N], b[N], c[N];
class solve {
	public:
		static void solution() {
			int n, m;
			cin >> n >> m ;
			for ( int i = 1 ; i <= n ;i ++)
			{
				cin >> a[i];
			}
			dp[1][0] = 0;
			dp[1][1] = a[1];
			for(int i = 1; i <= n ;i ++ )
			{
				dp[i][0] = max(dp[i-1][0],dp[i][0]);
				for(int j = 1 ; j <= min(m , i) ;j ++)
				{
					dp[i][j] = max(dp[i][j] , dp[i-1][j-1] + a[i]);
					dp[i+j][0] = max(dp[i][j],dp[i+j][0]);
				}
			}
			cout << dp[n][0] << endl;
 		}
};

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
//	cin >> T;
	while (T--) {
		solve::solution();
	}
	return 0;
}

躲藏 (nowcoder.com)

#include <bits/stdc++.h>

using namespace std;

#define LL long long

const LL mod = 2000120420010122;

LL dp[5];

int main() {
  ios::sync_with_stdio(0);

  string s;

  while (cin >> s) {
      for(int i = 1;i <= 4;i ++){
          dp[i] = 0;
      }

    for (int i = 0; i < s.size(); i++) {
      s[i] = tolower(s[i]);
      dp[1] = (dp[1] + (s[i] == 'c')) % mod;
      dp[2] = ((dp[2] + (s[i] == 'w') * dp[1])) % mod;
      dp[3] = ((dp[3] + (s[i] == 'b') * dp[2])) % mod;
      dp[4] = ((dp[4] + (s[i] == 'c') * dp[3])) % mod;
    }

    cout << dp[4] % mod << '\n';
  }
  return 0;
}

2 .状压dp

P1896 [SCOI2005] 互不侵犯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<iostream>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
#define ll long long
#define endl "\n"
typedef long long LL;

const int N = 12, M = 1 << 10, K = 110;

int n, m;
vector<int> state;
int cnt[M];
vector<int> head[M];
LL f[N][K][M];
bool check(int state)
{
	for(int i = 0 ; i < n ;i ++)
	{
		if((state >> i & 1) & (state >> (i + 1) & 1 ))
			return false;
	}
	return true;
}

int count(int state)
{
	int res = 0 ;
	for(int i = 0 ; i < n ;i ++)
	{
		 res += state >> i & 1;
	}
	return res;
}
int main() {
	scanf("%d%d", &n, &m);
	//筛选合法状态
	for(int i = 0 ; i < 1 << n ;i ++)
	{
		if(check(i))
		{
            state.push_back(i);
            cnt[i] = count(i);
		}
	}
	//合法转移
	int len = state.size();
	//cout << len ;
	for(int i = 0 ; i < len; i ++)
	{
		for(int j = 0; j < len ;j ++)
		{
			int a = state[i] , b = state[j];

			if((a & b)==0&&check(a | b))
			{
				head[i].push_back(j);
				//cout <<head[i].size()<<" ";
			}
		}
	}
	f[0][0][0] = 1;
	for(int i = 1 ; i <= n + 1 ;i++)
	{
		for(int j = 0 ;j <= m ;j++)
		{
			for(int a = 0 ; a < len ; a++)
			{
				for(int b : head[a])
				{
					int c = cnt[state[a]];
					if(j >= c)
						f[i][j][a] += f[i-1][j-c][b];
				}
			}
		}
	}
	cout << f[n+1][m][0] << endl; 
	return 0;
}

P2704 [NOI2001] 炮兵阵地 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
#define PII pair<int,int>
#define ll long long
const int N=110;
const int M=1<<10;
int n,m;
char a[N][N];
int dp[2][M][M];
int g[N];//这一行炮兵的位置是否合法
vector<int> state;
int cnt[M];
//合法筛选,一行内相邻的1必须间隔2个
bool check(int state)
{
	for(int i = 0 ;i < m;i++)
	{
		if((state >> i & 1)&&((state >> (i + 1) & 1)||(state >> (i + 2) & 1)))
			return false;
	}
	return true;
}
//查询1的个数
int count(int state)
{
	int res=0;
	for(int i=0;i<m;i++)
	{
		res+= state>>i & 1; 
	}
	return res;
}
int  main()
{
	cin>>n >>m;
	//输入
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<m;j++)
		{
			cin>>a[i][j];
			if(a[i][j]=='H')//把H用1来代替,方便后面计算
				g[i] += 1 << j;
		}
	}
	//筛选一行合法状态
	for(int i= 0 ;i< 1<<m;i++)
	{
		if(check(i))
		{
			state.push_back(i);
			cnt[i] = count(i);
		}	
	}
	//筛选可以转移的合法状态
	int len = state.size();
	dp[0][0][0] = 0;
	for(int i=1 ;i <=n+2;i ++)
	{
		for(int j= 0 ;j<len ;j++)
		{
			for(int k = 0 ; k <len ;  k++)
			{
				for(int u = 0 ;u <len ; u ++)
				{
					int a = state[j] , b = state[k] ,c = state[u];
					if((a&b)|(b&c)|(a&c)) continue;
					if((g[i] & b )| (g[i-1] & a))  continue;
					dp[i&1][j][k] = max(dp[i&1][j][k],dp[(i-1)&1][u][j] + cnt[b]);
				}
			}
		}
	}
	cout << dp[(n+2)&1][0][0] <<endl;
	return 0;
}

P2831 [NOIP2016 提高组] 愤怒的小鸟 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

#define x first
#define y second

using namespace std;

typedef pair<double, double> PDD;

const int N = 18, M = 1 << 18;
const double eps = 1e-8;

int n, m;
PDD q[N];
int path[N][N];
int f[M];

int cmp(double x, double y)
{
    if (fabs(x - y) < eps) return 0;
    if (x < y) return -1;
    return 1;
}

int main()
{
    int T;
    cin >> T;
    while (T -- )
    {
        cin >> n >> m;
        for (int i = 0; i < n; i ++ ) cin >> q[i].x >> q[i].y;
        
        memset(path, 0, sizeof path);
        for (int i = 0; i < n; i ++ )
        {
            path[i][i] = 1 << i;
            for (int j = 0; j < n; j ++ )
            {
                double x1 = q[i].x, y1 = q[i].y;
                double x2 = q[j].x, y2 = q[j].y;
                if (!cmp(x1, x2)) continue;
                double a = (y1 / x1 - y2 / x2) / (x1 - x2);
                double b = y1 / x1 - a * x1;
                
                if (cmp(a, 0) >= 0) continue;
                int state = 0;
                for (int k = 0; k < n; k ++ )
                {
                    double x = q[k].x, y = q[k].y;
                    if (!cmp(a * x * x + b * x, y)) state += 1 << k;
                }
                path[i][j] = state;
            }
        }
        
        memset(f, 0x3f, sizeof f);
        f[0] = 0;
        for (int i = 0; i + 1 < 1 << n; i ++ )
        {
            int x = 0;
            for (int j = 0; j < n; j ++ )
                if (!(i >> j & 1))
                {
                    x = j;
                    break;
                }
            
            for (int j = 0; j < n; j ++ )
                f[i | path[x][j]] = min(f[i | path[x][j]], f[i] + 1);
        }
        
        cout << f[(1 << n) - 1] << endl;
    }
    
    return 0;
}

3 . 数位dp

P8764 [蓝桥杯 2021 国 BC] 二进制问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<cstdio>
#include<iostream>
#include<map>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#define int long long 
#define pii pair<int,int>
#define endl "\n"
#define IL inline
using namespace std;
const int N = 1e6 + 10;
const int mod= 1e9+7;
int n, m;
int jc[100];
IL void init()
{
	int sum = 1;
	jc[0] = 1;
	for(int i=1; i<= 100 ; i ++)
	{
		sum *= i;
		jc[i] = sum ;
	}
}

int  C(int  b, int  a) // 计算组合(b在下面,a在上面)
{
    int sum = 1;
    for (int i = b, j = 1; j <= a; i--, j++)
        sum = sum * i / j;
    return sum;
}

IL void solve()
{
	vector<int> nums;
	while(n) nums.push_back(n%2) , n /= 2;

	int len = nums.size();
	int res = 0 ;
	int last = 0 ; // 一的个数 

	for(int i = len - 1 ; i >= 0 ; i --)
	{
		if(nums[i]==1)
		{
			if((m - last) >= 0 )
				res += C(i , m - last);
			last ++;
		}
       // cout << res << '\n';
		if(last > m)
			break;
		if(last == m && !i)
			res ++;
	}
	cout << res ;
}

signed main()
{
	init();
	cin >> n >> m;
	solve();
  	return 0;
}

P4317 花神的数论题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<bits/stdc++.h>
#define int long long 
#define pii pair<int,int>
#define endl "\n"
#define IL inline
using namespace std;
const int N = 1e6 + 10;
const int mod= 1e7 + 7;																																																												;
int C[110][110];
class solve{
	public:
		//快速幂
		static int qmi(int x,int y)
		{
			int res = 1 ;

			while(y)
			{
				if(y & 1)
					res = res * x % mod ;
				y >>= 1;
				x = x * x % mod;
			}
			
			return res ;
		}
		//求解组合数  
		static void init()
		{
			//防止数组越界
			C[0][0] = 1;
			for( int i = 1 ;i <= 100 ; i ++)
			{
				C[i][0] = 1;
				C[i][1] = i;
			}

			for(int i = 2 ; i <= 100 ; i ++)
			{
				for(int j = 2 ; j <= i ; j ++)
				{
					C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]);
				}
			}
		}

	    static void solution()
	    {
	    	 int n ;
	    	 cin >> n; 

	    	 vector<int> nums ;
	    	 vector<int> answered(100);
	    	 answered.clear();
	    	 while(n) nums.push_back(n & 1) , n >>= 1;

	    	 int last = 0;//记录出现了多少个一
	    	 int answer = 1 ;// 答案
	    	 int len = nums.size() ;

	    	 for(int i = len - 1 ; i >= 0; i --)
	    	 {
	    	 	int x = nums[i] ;

	    	 	if(x) 
	    	 	{
	    	 		for(int j = 0; j <= i ; j ++)
	    	 		{
	    	 			answered[j + last] += C[i][j];
	    	 		}
	    	 	}
	    	 	if(x == 1)
	    	 		last ++;
	    	 }
	    	 //求解答案
	    	 answered[last] ++;
	    	 for(int i = 1 ;i <= len ; i ++)
	    	 {
	    	 	if(answered[i])
	    	 	{
	    	 		answer = answer * qmi(i , answered[i]) % mod;
	    	 	}
	    	 }
	    	 //cout << answer << endl;
	    	 cout << answer << endl;
	    }
};

signed main()
{
	int T = 1;
//	cin >> T;
	solve::init();
	while(T--)
	{
		solve::solution();
	}
  	return 0;
}

P1836 数页码 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<cstdio>
#include<iostream>
#include<map>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define ll long long 
#define PII pair<int,int>
#define endl "\n"
const int N = 30;
int a[N];
ll f[N][10];
//快速幂
ll qmi(int x,int y)
{
	ll res = 1;
	while(y)
	{
		if(y & 1)
			res = res * x;
		x = x * x;
		y >>= 1;
	}
	return res;
}
//预处理
void init()
{
	for(int i = 1 ; i <= N ; i ++)
	{
		for(int j = 0 ;j <= 9 ; j ++)
		{
			if(j==0)
			{
				f[i][0] = f[i-1][9];
			}else 
			{
				f[i][j] = f[i][j-1] + (f[i][0] + qmi(10,i-1)*j);
			}
		}
	}
}
ll get(ll x)
{
	ll res=0;
	vector<int> v;
	int num=x;
	while(num) v.push_back(num%10),num/=10;
	//比如是7264
	for(int i = v.size()- 1 ;i >= 0; i--)
	{
		if(v[i] == 0)
			continue;
		res += f[i + 1][v[i]-1]; // 拆成1 - 6999 和 7000 - 7264
		res += (x%qmi(10,i)+1)*v[i]; // 第一次循环,这里是算7000 - 7264 中7的个数
	}
	return res;
}
int main()
{
	init();
	int n ;
	cin >> n ;
	cout << get(n);
  	return 0;
}

P2657 [SCOI2009] windy 数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<cstdio>
#include<iostream>
#include<map>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define ll long long 
#define PII pair<int,int>
#define endl "\n"
const int N = 11;
const int mod= 1e9+7;
ll f[N][10];
//预处理
void init()
{
	for(int i = 0; i<= 9 ; i ++) f[1][i] = 1;
	for(int i = 2 ; i < N ; i ++)
	{
		for(int j = 0 ; j <= 9 ;j ++)
		{
			for(int k = 0 ; k <=9 ; k ++)
			{
				if(abs(j - k) >= 2)
				{
					f[i][j] += f[i-1][k];
				}
			}
		}
	}
}
ll dp(ll p)
{
	if(!p) return 0;
	ll res=0;
	vector<int> v;
	ll num=p;
	while(num) v.push_back(num%10),num/=10;
	
	int last = -2;
	for(int i = v.size() -1  ;i >= 0 ; i--)
	{
		int x = v[i];
		for(int j = i == v.size() - 1 ;j <  x ; j++)
		{
			if(abs(j - last) >= 2)
				res += f[i + 1][j] ;
		}
		if(abs(x - last) >= 2) last =x;
		else break; 
		if(!i) res ++;
	}

	for(int i=1 ; i < v.size() ; i ++)
	{
		for(int j = 1 ; j <= 9; j ++)
		{
			res += f[i][j];
		}
	}
	return res ;
}
int main()
{
	init();
	int l , r ;
	cin >> l >> r ;
	cout << dp(r) - dp( l-1) <<endl;
  	return 0;
}

P2602 [ZJOI2010] 数字计数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define maxn 14
#define LL long long
LL dp[maxn][10][10];
LL L,R;
LL ans[10][2];
int a[maxn],num;
inline LL quick(LL a,LL b)
{
	LL s=1;
	while(b)
	{
		if(b&1) s*=a;
		b>>=1;
		a*=a;
	}
	return s;
}
inline void slove(LL x,int pd)
{
	memset(dp,0,sizeof(dp));
	num=0;
	memset(a,0,sizeof(a));
	while(x)
	{
		a[++num]=x%10;
		x/=10;
	}//分解数位 
	for(re int i=0;i<=9;i++) dp[1][i][i]=1;//初始化
	for(re int i=2;i<=num;i++)//枚举位数
		for(re int j=0;j<=9;j++)//当前最高位
		{
			for(re int k=0;k<=9;k++)//次高位
			{
				for(re int p=0;p<=9;p++)
					dp[i][j][p]+=dp[i-1][k][p];
			}
			dp[i][j][j]+=quick(10,i-1);//乘法原理
		}
	for(re int i=1;i<num;i++)//位数比x小的,一定能够满足条件
		for(re int j=1;j<=9;j++)//不能有前导零
			for(re int k=0;k<=9;k++)
				ans[k][pd]+=dp[i][j][k];
	for(re int i=1;i<a[num];i++)//位数相同,但最高位比x小
		for(re int k=0;k<=9;k++)
			ans[k][pd]+=dp[num][i][k];
	for(re int i=num-1;i>=1;i--)//当前不同的那一位,[i+1,num]与x完全相同 
	{
		for(re int j=0;j<a[i];j++)//不同的这一位也必须必对应x位置上的数小
		{
			for(re int k=0;k<=9;k++)
				ans[k][pd]+=dp[i][j][k];
		}
		for(re int p=num;p>i;p--)
				ans[a[p]][pd]+=a[i]*quick(10,i-1);
        //由于我们保证[i+1,num]相同,那么这些数码也应该计入答案,于是还是一个乘法原理
	}
    //但是这个dp全程都不能处理出x是否满足条件
    //因为最后也只是判断第一位上的数比给定数的第一位小
    //所以slove(x)其实求得是[0,x)满足条件的数的个数
}
int main()
{
	scanf("%lld%lld",&L,&R);
	slove(R+1,0),slove(L,1);
	for(re int i=0;i<=9;i++)
		printf("%lld ",ans[i][0]-ans[i][1]);
	putchar(10);
	return 0;
}

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Smile灬凉城666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值