A-HDU1087 http://acm.hdu.edu.cn/showproblem.php?pid=1087
相当于从数组a中找一个最优序列,我们设要找的序列为A,序列A满足两个条件,一是A中的元素大小满足单调递增,二是A中所有元素的和最大,输出这个最大值。
令f[i]表示以第i个元素结尾的A序列的最大值,则有f[i]=MAX{ f[j]+a[i] | j<i } ans=MAX{f[i]};
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main() 4 { 5 int N,i,j,k,ans; 6 int f[1005],a[1005]; 7 while(cin>>N&&N){ 8 memset(f,0,sizeof(f)); 9 ans=0; 10 for(i=1;i<=N;++i) cin>>a[i]; 11 for(i=1;i<=N;++i){ 12 int maxn=0; 13 for(j=1;j<i;++j){ 14 if(a[j]<a[i]&&f[j]>maxn) maxn=f[j]; 15 } 16 f[i]=maxn+a[i]; 17 ans=max(ans,f[i]); 18 } 19 cout<<ans<<endl; 20 } 21 return 0; 22 }
B-HDU5586 http://acm.hdu.edu.cn/showproblem.php?pid=5586
对于数组A可以选定任意一段连续的区间[l,r]将这段区间的值改变为: A[i]=(1890*A[i]+143)%10007; 求更改之后A数组的总和的最大值。
不妨这么想,这个最大值就是未改变之前的A数组的总和加上改变的那段区间改变以后增加的值X,问题就转化为求最大的X,
设B[i]=(1890*A[i]+143)%10007,C[i]=B[i]-A[i]; 显然X就是C数组的一个最大子段和,找到之后输出SUM{A[i]}+X即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main() 4 { 5 int N,M,i,j,k,t,a,b; 6 while(scanf("%d",&N)==1){ 7 int s=0,maxn=0,sumn=0; 8 for(i=1;i<=N;++i){ 9 scanf("%d",&a); 10 s+=a; 11 b=1890*a+143; 12 if(b>10006) b=b%10007-a; 13 else b-=a; 14 sumn+=b; 15 if(sumn>maxn) maxn=sumn; 16 if(sumn<0) sumn=0; 17 } 18 printf("%d ",s+maxn); 19 } 20 return 0; 21 }
C-uva10910 https://vjudge.net/problem/UVA-10910
F(N,T,P)表示N门不同的课程,总共得分T分,没门至少得分P分,求不同的得分方案总数。
1是dp,令f(i,j)表示前i门课程得了j分的方案个数,枚举最后一门课程得分k,有f[i][j]=SUM{f[i-1][j-k] | P<=k<=T&&0<=j-k<=T}
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 int f[105][105]; 5 int main() 6 { 7 int T,N,P,cas,i,j,k; 8 cin>>cas; 9 while(cas--){ 10 cin>>N>>T>>P; 11 memset(f,0,sizeof(f)); 12 f[0][0]=1; 13 for(i=1;i<=N;++i) 14 { 15 for(j=P*i;j<=T;j++) 16 { 17 for(k=P;k<=T;++k) 18 { 19 if(j-k<=T&&j-k>=0) 20 f[i][j]+=f[i-1][j-k]; 21 } 22 } 23 } 24 cout<<f[N][T]<<endl; 25 } 26 return 0; 27 }
2-组合数学
利用组合数学,题目转换为将T-N*P个小球(相同)放入N个盒子(不同)的方案个数,显然是C(T-N*P+N-1,T-N*P)-------->数学公式我只会背不会推导
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 LL C(LL N,LL M) 5 { 6 LL ans=1; 7 for(LL i=1;i<=M;++i) 8 { 9 ans=ans*(N-i+1)/i; 10 } 11 return ans; 12 } 13 int main() 14 { 15 LL N,T,P; 16 int k; 17 cin>>k; 18 while(k--){ 19 cin>>N>>T>>P; 20 cout<<C(T-N*P+N-1,T-N*P)<<endl; 21 } 22 return 0; 23 }
D-HDU1243 http://acm.hdu.edu.cn/showproblem.php?pid=1243
一个标准的LCS模型,只不过多了权值,稍微改下转移方程就好了,令kill(i)表示杀死第i个人的得分
f[i][j]=MAX{f[i-1][j-1]+kill(i) | if(s1[i]==s2[j]) , f[i-1][j] , f[i][j-1] }
1 #include<bits/stdc++.h> 2 using namespace std; 3 int f[2105][2105]; 4 int value[30]; 5 char s1[2105],s2[2105],s[2105]; 6 int main() 7 { 8 int N; 9 int i,j,k,n,m; 10 while(cin>>N){ 11 cin>>s+1; 12 for(i=1;i<=N;++i) cin>>value[s[i]-'a']; 13 cin>>s1+1>>s2+1; 14 int len1=strlen(s1+1); 15 int len2=strlen(s2+1); 16 memset(f,0,sizeof(f)); 17 for(i=1;i<=len1;++i){ 18 for(j=1;j<=len2;++j){ 19 if(s1[i]==s2[j]){ 20 f[i][j]=max(f[i][j],f[i-1][j-1]+value[s1[i]-'a']); 21 } 22 f[i][j]=max(f[i][j],max(f[i-1][j],f[i][j-1])); 23 } 24 } 25 cout<<f[len1][len2]<<endl; 26 } 27 return 0; 28 }
E-HDU2845 http://acm.hdu.edu.cn/showproblem.php?pid=2845
其实就是求最大不连续子段和,先求出每一行的最大不连续子段和,再把每一行求出的值看作一个序列再求一次最大不连续子段和就是答案。
令f[i]表示前i个元素中的最大不连续子段和,有f[i]=max(f[i-1],a[i]+f[i-2]);
1 #include<bits/stdc++.h> 2 using namespace std; 3 int dp[200005]; 4 int h[200005]; 5 int book[200005]; 6 int n,m; 7 int init(int a[],int len) 8 { 9 dp[0]=0; 10 dp[1]=a[1]; 11 for(int i=2;i<=len;++i) 12 dp[i]=max(a[i]+dp[i-2],dp[i-1]); 13 return dp[len]; 14 } 15 int main() 16 { 17 int i,j,k; 18 while(cin>>n>>m){int s1=0,s2=0; 19 for(i=1;i<=n;++i){ 20 for(j=1;j<=m;++j) 21 scanf("%d",&h[j]); 22 book[i]=init(h,m); 23 } 24 printf("%d ",init(book,n)); 25 } 26 return 0; 27 }