第1行:整数序列的长度N(2 <= N <= 50000) 第2 - N+1行:N个整数 (-10^9 <= S[i] <= 10^9)
输出循环数组的最大子段和。
6 -2 11 -4 13 -5 -2
20
1 #include<bits/stdc++.H> 2 using namespace std; 3 typedef long long LL; 4 5 int a[100010]; 6 int n; 7 const LL inf=1e17; 8 int main() 9 { 10 LL d=0; 11 scanf("%d",&n); 12 for(int i=0;i<n;i++) scanf("%d",&a[i]),d+=a[i]; 13 LL sum=0; 14 LL ans1=-inf; 15 for(int i=0;i<n;i++) 16 { 17 sum+=a[i]; 18 if(sum>ans1) ans1=sum; 19 if(sum<0) sum=0; 20 } 21 22 sum=0; 23 LL ans2=inf; 24 for(int i=0;i<n;i++) 25 { 26 sum+=a[i]; 27 if(sum<ans2) ans2=sum; 28 if(sum>0) sum=0; 29 } 30 printf("%lld ",max(ans1,d-ans2)); 31 }
循环数组的最大字段和,有两种状态,要么是从中间截取一段,不会跨越头尾;第二种是跨越头尾,在这种情况下,最大字段和应该是从序列中取出来一个最小字段和,然后用总的减掉即可
求最大字段和就是不断记录一个sum,用sum去更新ans
输入1个数N,N = 100表示1元钱。(1 <= N <= 100000)
输出Mod 10^9 + 7的结果
5
4
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int n; 5 int v[20]={0,1,2,5,10,20,50,100,200,500,1000,2000,5000,10000}; 6 int dp[100010]; 7 const int mod=1e9+7; 8 int main() 9 { 10 scanf("%d",&n); 11 fill(dp,dp+n+1,1); 12 for(int i=2;i<=13;i++) 13 { 14 for(int j=v[i];j<=n;j++) 15 { 16 dp[j]=(dp[j]+dp[j-v[i]])%mod; 17 } 18 19 } 20 printf("%d ",dp[n]); 21 }
定义dp[i][j]为前i件物品,背包容量为j时,组合的方案数,那么dp[i][j]=sigma(dp[i-1][j-k*v[i]]),0<=k<=j/v[i],
化简方法:dp[i][j-v[i]]=sigma(dp[i-1][j-k*v[i]]),1<=k<=j/v[i]
那么 dp[i][j]=dp[i][j-v[i]]+dp[i-1][j]
滚动数组,从小到大递推
一行,包含一个整数n。 (0 < n <= 2000)
一行表示结果,由于结果巨大,输出它对1000000007取余数的结果。
10
60
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 5 const int mod=1e9+7; 6 7 int n; 8 LL dp[2020][25]; 9 int main() 10 { 11 scanf("%d",&n); 12 dp[1][1]=1; 13 dp[0][0]=1; 14 for(int i=1;i<=n;i++) 15 { 16 for(int j=1;j<=20;j++) 17 { 18 LL tmp=0; 19 for(int k=0;k<=i-1;k++) 20 { 21 cout<<j<<" "<<dp[k][j-2]<<endl; 22 tmp=(tmp+dp[k][j-1]*dp[i-1-k][j-1]+dp[k][j-1]*dp[i-1-k][j-2]+dp[k][j-2]*dp[i-1-k][j-1])%mod; 23 } 24 dp[i][j]=tmp; 25 } 26 } 27 LL ans=0; 28 for(int i=1;i<=20;i++) 29 ans=(ans+dp[n][i])%mod; 30 printf("%lld ",ans); 31 }
这里提交的是c++11标准,代码中可能访问-1下标,
n个节点的AVL树的种类数,定义状态dp[i][j]为节点数为i, j为高度 的形态的AVL树的种类数目,
那么dp[i][j] = dp[k][j-1] * dp[i-1-k][j-1] + dp[k][j-2] * dp[i-1-k][j-1] + dp[k][j-1] * dp[i-1-k][j-2] ,即为左右子树分类考虑的dp方式
初始化 dp[0][0]=1,dp[1][1]=1;
第1行:字符串a(a的长度 <= 1000)。 第2行:字符串b(b的长度 <= 1000)。
输出a和b的编辑距离
kitten sitting
3
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=1010; 5 char a[maxn]; 6 char b[maxn]; 7 int dp[maxn][maxn]; 8 9 int main() 10 { 11 scanf("%s%s",a+1,b+1); 12 int len1=strlen(a+1); 13 int len2=strlen(b+1); 14 int len=max(len1,len2); 15 for(int i=0;i<=len;i++) dp[i][0]=dp[0][i]=i; 16 for(int i=1;i<=len1;i++) 17 { 18 for(int j=1;j<=len2;j++) 19 { 20 dp[i][j]=min(dp[i][j-1],dp[i-1][j])+1; 21 if(a[i]!=b[j]) dp[i][j]=min(dp[i][j],dp[i-1][j-1]+1); 22 else dp[i][j]=min(dp[i][j],dp[i-1][j-1]); 23 } 24 } 25 printf("%d ",dp[len1][len2]); 26 27 }
要使得两个字符串变得相同,有替换 ,插入,删除三种操作,很显然拿两个指针分别在a/b串上走,
然后对ab所指向的字符 分别考虑是做什么操作,是替换还是插入删除
定义dp[i][j]为a中前i个与b中前j个变得相同 应该做多少操作
显然 dp[i][j] = min(dp[i-1][j],dp[i][j-1])+1;
再考虑 替换操作 if ( a[i]==b[j] ) dp[i][j] = dp[i-1][j-1];
else dp[i][j] = dp[i-1][j-1] + 1;