DP 打卡~~~~

为什么什么事都做不好、、

链接:https://ac.nowcoder.com/acm/problem/21302
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除
答案对1e9+7取模
输入描述:

输入一个字符串,由数字构成,长度小于等于50

输出描述:

输出一个整数

示例1
输入
复制

132

输出
复制

3

示例2
输入
复制

9

输出
复制

1

示例3
输入
复制

333

输出
复制

7

示例4
输入
复制

123456

输出
复制

23

示例5
输入
复制

00

输出
复制

3

备注:

n为长度
子任务1: n <= 5
子任务2: n <= 20
子任务3: 无限制

  • DP[i][k]表示到从1 到 i mod 3余数为k的子序列
  • 对于是不是被3 整除的子序列 可以考虑每一位被3 除的余数
  • 比如 mod 3 =1
  • dp[i][1]
  • 这个数可以和子序列为0 的数 连接 ,也可以直接选dp[i-1][1]的序列(直接忽视这个1)或者自己作为序列1 (+1)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
char s[55];
ll dp[55][5];
int main()
{
	scanf("%s",s+1);
	int len=strlen(s+1);
	dp[0][1]=dp[0][2]=dp[0][0]=0;
	for(int i=1;i<=len;i++)
	{
		if((s[i]-'0')%3==0)
		{
			dp[i][0]=2*dp[i-1][0]+1;
			dp[i][1]=2*dp[i-1][1];
			dp[i][2]=2*dp[i-1][2];
		}else if((s[i]-'0')%3==1)
		{
			dp[i][0]=dp[i-1][0]+dp[i-1][2];
			dp[i][1]=dp[i-1][1]+dp[i-1][0]+1;
			dp[i][2]=dp[i-1][1]+dp[i-1][2];
		}else 
		{
			dp[i][0]=dp[i-1][0]+dp[i-1][1];
			dp[i][1]=dp[i-1][1]+dp[i-1][2];
			dp[i][2]=dp[i-1][2]+dp[i-1][0]+1;
		}
	}
	printf("%lld",dp[len][0]%mod);
}
  • 判断可行性DP
  • 链接:https://ac.nowcoder.com/acm/problem/21303
    来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
给你一个合法的括号序列s1,每次你可以删除一个"()"
你可以删除0个或者多个"()"
求能否删成另一个括号序列s2
输入描述:

第一行输入一个字符串s (2 ≤ |s| ≤ 100)
第二行输入一个字符串t (2 ≤ |t| ≤ 100 )

输出描述:

如果可以输出"Possible"
否则输出"Impossible"

示例1
输入
复制

(())
()

输出
复制

Possible

示例2
输入
复制

()
()

输出
复制

Possible

示例3
输入
复制

(()()())
((()))

输出
复制

Impossible

示例4
输入
复制

((())((())())())
(()(())())

输出
复制

Possible

示例5
输入
复制

((())((())())())
((()()()()()))

输出
复制

Impossible

备注:

子任务1: |s| <= 10
子任务2: |s| <= 20
子任务3: 无限制

  • dp[i][j][k]表示s1[i]和s2[j]位置在k = 删掉的’(‘数 - 删掉的’)'数时可否匹配(判断是否可行)
  • k=0相当减去若干个个()的括号
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int dp[N][N][N];
char s[N],t[N];
int main()
{
	scanf("%s",s+1);
	scanf("%s",t+1);
	int ls=strlen(s+1),lt=strlen(t+1);
	dp[0][0][0]=1;
	for(int i=0;i<ls;i++)
	{
		for(int j=0;j<=lt;j++)
		{
			for(int k=0;k<=ls/2;k++)
			{
				if(dp[i][j][k]==0) continue;
				if(!k&&s[i+1]==t[j+1]) dp[i+1][j+1][k]=1;
				if(s[i+1]=='(') dp[i+1][j][k+1]=1;
				else if(k)
				{
					dp[i+1][j][k-1]=1;
				}
			}
		}
	}
	if(dp[ls][lt][0]) puts("Possible");
	else puts("Impossible");
}

链接:https://ac.nowcoder.com/acm/problem/21313
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
牛牛喜欢整数序列,他认为一个序列美丽的定义是
1:每个数都在0到40之间
2:每个数都小于等于之前的数的平均值
具体地说:for each i, 1 <= i < N, A[i] <= (A[0] + A[1] + … + A[i-1]) / i.
3:没有三个连续的递减的数

现在给你一个序列,每个元素是-1到40,你可以将序列中的-1修改成任意的数,求你可以得到多少个美丽序列,答案对1e9+7取模

输入描述:

第一行输入一个整数n (1 ≤ n ≤ 40)

第二行输入n个整数

输出描述:

输出一个整数

示例1
输入
复制

2
3 -1

输出
复制

4

示例2
输入
复制

3
5 3 -1

输出
复制

2

示例3
输入
复制

3
-1 0 40

输出
复制

0

示例4
输入
复制

11
-1 40 -1 -1 -1 10 -1 -1 -1 21 -1

输出
复制

579347890

备注:

子任务1: n <= 10
子任务2: n <= 20
子任务3: 无限制

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[50];
ll dp[45][41][3][1601];
const int mod=1e9+7;
int main()
{
	int n;
	scanf("%d",&n);dp[0][0][0][0]=1;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)//枚举到第i位  
	{
		for(int j=0;j<=40;j++) //上一位的数值 
		{
			for(int k=0;k<=1;k++)//k==0 末尾的递降序列的长度为1 
			{
				for(int s=0;s<=(i-1)*40;s++)//前缀和 
				{
					if(dp[i-1][j][k][s]==0) continue;int f=0,t=40;
					if(a[i]!=-1) f=t=a[i];
					for(int h=f;h<=t;h++) 
					{
						int kk=h<j?k+1:0;
						if((i-1)*h>s||kk>=2) continue; 
						(dp[i][h][kk][s+h]+=dp[i-1][j][k][s])%=mod;
					}
				}
				 
			 } 
		}
	}
	ll ans=0;
	for(int g=0;g<=40;g++)
    for(int i=0;i<2;i++)
    for(int j=0;j<=1600;j++)
    {
    	(ans+=dp[n][g][i][j])%=mod;
	}
	printf("%lld\n",ans%mod); 
}

链接:https://ac.nowcoder.com/acm/problem/21314
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
牛牛正在打一场CF
比赛时间为T分钟,有N道题,可以在比赛时间内的任意时间提交代码
第i道题的分数为maxPoints[i],题目的分数随着比赛的进行,每分钟减少pointsPerMinute[i]
这是一场比较dark的Cf,分数可能减成负数
已知第i道题需要花费 requiredTime[i] 的时间解决
请问最多可以得到多少分

输入描述:

第一行输入两个整数N,T (1 ≤ N ≤ 50, 1 ≤ T ≤ 100000)
第二行输入n个整数maxPoints[i]
第三行输入n个整数pointsPerMinute[i]
第四行输入n个整数requiredTime[i]
1 ≤ maxPoints[i],pointsPerMinute[i],requiredTime[i] ≤ 100000

输出描述:

输出一个整数

示例1
输入
复制

1 74
502
2
47

输出
复制

408

示例2
输入
复制

2 40000
100000 100000
1 100000
50000 30000

输出
复制

0

示例3
输入
复制

3 75
250 500 1000
2 4 8
25 25 25

输出
复制

1200

示例4
输入
复制

3 30
100 100 100000
1 1 100
15 15 30

输出
复制

97000

备注:

子任务1: n <= 10
子任务2: n <= 20
子任务3: 无限制

首先可以列出一个数学不等式求出node x 在node y 之前处理的条件然后由这个条件进行sort 之后的处理类似背包

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=55;
struct node
{
	ll maxx,de,t;
}v[N];
ll dp[100010];
int cmp(node x,node y)
{
	return x.de*y.t>x.t*y.de;
}
int main()
{
	int t,n;
	scanf("%d%d",&n,&t);
	for(int i=0;i<n;i++) scanf("%lld",&v[i].maxx);
	for(int i=0;i<n;i++) scanf("%lld",&v[i].de);
	for(int i=0;i<n;i++) scanf("%lld",&v[i].t);
	sort(v,v+n,cmp);ll ans=0;
	for(int i=0;i<n;i++)
	{
	    for(int j=t;j>=v[i].t;j--)
	    {
	    	dp[j]=max(dp[j],dp[j-v[i].t ]+(v[i].maxx-j*v[i].de ));
	    	
		}
	}
	for(int i=0;i<=t;i++) ans=max(ans,dp[i]); 
	printf("%lld\n",ans);
} 
Mr. Young's Picture Permutations
Time Limit: 1000MS		Memory Limit: 65536K
Total Submissions: 3031		Accepted: 1144

Description
Mr. Young wishes to take a picture of his class. The students will stand in rows with each row no longer than the row behind it and the left ends of the rows aligned. For instance, 12 students could be arranged in rows (from back to front) of 5, 3, 3 and 1 students.

X X X X X

X X X

X X X

X


In addition, Mr. Young wants the students in each row arranged so that heights decrease from left to right. Also, student heights should decrease from the back to the front. Thinking about it, Mr. Young sees that for the 12-student example, there are at least two ways to arrange the students (with 1 as the tallest etc.):

 1  2  3  4  5     1  5  8 11 12

 6  7  8           2  6  9

 9 10 11           3  7 10

12                 4


Mr. Young wonders how many different arrangements of the students there might be for a given arrangement of rows. He tries counting by hand starting with rows of 3, 2 and 1 and counts 16 arrangements:

123 123 124 124 125 125 126 126 134 134 135 135 136 136 145 146

45  46  35  36  34  36  34  35  25  26  24  26  24  25  26  25

6   5   6   5   6   4   5   4   6   5   6   4   5   4   3   3


Mr. Young sees that counting by hand is not going to be very effective for any reasonable number of students so he asks you to help out by writing a computer program to determine the number of different arrangements of students for a given set of rows.

Input
The input for each problem instance will consist of two lines. The first line gives the number of rows, k, as a decimal integer. The second line contains the lengths of the rows from back to front (n1, n2,..., nk) as decimal integers separated by a single space. The problem set ends with a line with a row count of 0. There will never be more than 5 rows and the total number of students, N, (sum of the row lengths) will be at most 30.

Output
The output for each problem instance shall be the number of arrangements of the N students into the given rows so that the heights decrease along each row from left to right and along each column from back to front as a decimal integer. (Assume all heights are distinct.) The result of each problem instance should be on a separate line. The input data will be chosen so that the result will always fit in an unsigned 32 bit integer.

Sample Input

1
30
5
1 1 1 1 1
3
3 2 1
4
5 3 3 1
5
6 5 4 3 2
2
15 15
0

Sample Output

1
1
16
4158
141892608
9694845

Source
Greater New York 2004
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;

int lim[6];
int main()
{
	int n;
	while(scanf("%d",&n))
	{
	    
		if(n==0) return 0;memset(lim,0,sizeof(lim));
		for(int i=0;i<n;i++)
		{
			scanf("%d",&lim[i]);
		}
		ll f[lim[0]+1][lim[1]+1][lim[2]+1][lim[3]+1][lim[4]+1];
		memset(f,0,sizeof(f));f[0][0][0][0][0]=1;
		for(int i=0;i<=lim[0];i++)
		{
			for(int j=0;j<=lim[1];j++)
			{
				for(int k=0;k<=lim[2];k++)
				{
					for(int h=0;h<=lim[3];h++)
					{
						for(int g=0;g<=lim[4];g++)
						{
						  if(i+1<=lim[0]) f[i+1][j][k][h][g]+=f[i][j][k][h][g];
						  if(j+1<=lim[1]&&(i>j)) f[i][j+1][k][h][g]+=f[i][j][k][h][g];
						  if(k+1<=lim[2]&&i>k&&j>k) f[i][j][k+1][h][g]+=f[i][j][k][h][g];
						  if(h+1<=lim[3]&&i>h&&j>h&&k>h) f[i][j][k][h+1][g]+=f[i][j][k][h][g];
						  if(g+1<=lim[4]&&i>g&&j>g&&k>g&&h>g) f[i][j][k][h][g+1]+=f[i][j][k][h][g];	
						}
					}
				}
			}
		}
		printf("%lld\n",f[lim[0]][lim[1]][lim[2]][lim[3]][lim[4]]);
	}
	
}
链接:https://ac.nowcoder.com/acm/contest/1041/B
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目。小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们研究最长公共上升子序列了。
小沐沐说,对于两个数列A和B,如果它们都包含一段位置不一定连续的数,且数值是严格递增的,那么称这一段数是两个数列的公共上升子序列,而所有的公共上升子序列中最长的就是最长公共上升子序列了。
奶牛半懂不懂,小沐沐要你来告诉奶牛什么是最长公共上升子序列。不过,只要告诉奶牛它的长度就可以了。数列A和B的长度均不超过3000。
输入描述:

第一行N,表示A,B的长度。
第二行,串A。
第三行,串B。

输出描述:

输出长度。

示例1
输入
复制

4
2 2 1 3
2 1 2 3

输出
复制

2

备注:

1≤N≤30001\leq N\leq 30001≤N≤3000,A,B中的数字不超过231−12^{31}-1231−1
#include<bits/stdc++.h>
using namespace std;
int a[3010],b[3010];
int dp[3010][3010];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&b[i]);
	}
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(a[i]==b[j])
			{
				for(int k=0;k<j;k++)
				{
					if(b[k]<a[i]) dp[i][j]=max(dp[i][j],dp[i-1][k]+1);
				}
			}else dp[i][j]=dp[i-1][j];
		    ans=max(ans,dp[i][j]);
		}
		
	}
	printf("%d\n",ans);
}
#include<bits/stdc++.h>
using namespace std;
int a[3010],b[3010],dp[3010];
int main()
{
	int n;scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int j=1;j<=n;j++) scanf("%d",&b[j]);int ans=0;
	for(int i=1;i<=n;i++)
	{
		int v=0;
		for(int j=1;j<=n;j++)
		{
			if(a[i]==b[j]) dp[j]=v+1; //dp[j]表示以dp[j]为结尾的最长公共上升子序列 
			else if(a[i]>b[j]) v=max(v,dp[j]);
			//如果这个值比a[i]小那么他也有可能成为这个序列的一个部分 v 表示在b[j]之前的子序列的最长长度 
			ans=max(ans,dp[j]);
		}
	}
	printf("%d\n",ans);
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值