老刘在网上放了dp的比赛,全?是dp;
菜如狗的lsj发现自己什么都不会,于是开了这篇随笔来巩固(重学)一下dp;
B - 最长等差数列
N个不同的正整数,找出由这些数组成的最长的等差数列。
例如:1 3 5 6 8 9 10 12 13 14
等差子数列包括(仅包括两项的不列举)
1 3 5
1 5 9 13
3 6 9 12
3 8 13
5 9 13
6 8 10 12 14
其中6 8 10 12 14最长,长度为5。
Input第1行:N,N为正整数的数量(3 <= N <= 10000)。
第2 - N+1行:N个正整数。(2<= Aii <= 10^9)Output最长等差数列的长度。Sample Input
10 1 3 5 6 8 9 10 12 13 14
Sample Output
5
先用sort拍一下序;dp【i】【u】表示结尾是a[i],倒数第二个是a[u]的等差数列的长度;那么我们就可以列出方程:
if(a[i]-a[u]==a[u]-a[k])dp[i][u]=dp[u][k]+1;
看似好像是n^3, 但仔细分析一下的话会发现由于u是递增的,所以a[i]-a[u]是递减的;所以a[u]-a[k]也是递减的,所以k是递增的;
有了这个想法,就不难写出n^2的算法了;
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #define xx getchar() 7 #define tmp 23 8 using namespace std; 9 int a[10001]; 10 short dp[10001][10001]; 11 int n; 12 short ans=0; 13 int read() 14 { 15 int x=0,f=1; 16 char ch; 17 ch=xx; 18 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=xx;} 19 while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=xx;} 20 return x*f; 21 } 22 int main() 23 { 24 n=read(); 25 for(int i=1;i<=n;i++) 26 a[i]=read(),dp[i][0]=1; 27 sort(a+1,a+n+1); 28 for(int i=2;i<=n;i++) 29 { 30 int k=0; 31 for(int u=1;u<i;u++) 32 { 33 int x=a[u]-(a[i]-a[u]); 34 int f=0; 35 while(k<=u) 36 { 37 if(a[k]==x){dp[i][u]=dp[u][k]+1;f=1;} 38 if(a[k]>x)break; 39 k++; 40 } 41 if(f==0)dp[i][u]=2; 42 ans=max(ans,dp[i][u]); 43 } 44 } 45 cout<<ans<<endl; 46 return 0; 47 }
C - 最大M子段和
N个整数组成的序列a1,a2,a3,…,an,将这N个数划分为 互不相交的M个子段,并且这M个子段的和是最大的。 如果M >= N个数中正数的个数,那么输出所有正数的和。
例如: -2 11 -4 13 -5 6 -2,分为2段,11 -4 13一段,6 一段,和为26。
Input第1行:2个数N和M,中间用空格分隔。N为整数的个数,M为划分为多少段。(2 <= N , M <= 5000)
第2 - N+1行:N个整数 (-10^9 <= aii <= 10^9)Output输出这个最大和Sample Input
7 2 -2 11 -4 13 -5 6 -2
Sample Output
26 设dp【i】【u】将前u个数分成i段的最大值;刚开始想的是这样的;do[i][u]=max(dp[i-1][u],dp[i][u-1]);dp[i][u]=max(dp[i-1][u-1]+a[u],dp[i][u-1]+a[u],dp[i][u]);但是这样是有问题的;dp[i-1][u-1]+a[u]并不错但dp【i】【u-1】+a[u]就不一定了;因为第i个不一定连续到了u-1;那么我们就想一下如何保证dp【i】【u-1】+a【u】是可行的;经过深思熟虑的思考(查题解);我们知道了这样一个方式:保证a[u-1]在i中;再开一个f[i][u]记录a[u]必选的最大值;那么就有f[i][u]=max(f[i-1][u-1]+a[u],f[i][u-1]+a[u]);那么dp[i][u]就可以改成dp[i][u]=max(dp[i-1][u-1],f[i][u]);这样就可以A掉此题;还值得说的就是对此题的空间优化了,因为f,dp数组都只和上一个f,dp有关,所以我们可以吧i给省略掉;
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #define xx getchar() 7 #define tmp 23 8 #define intt long long 9 using namespace std; 10 int m; 11 int n; 12 short ans=0; 13 int read() 14 { 15 int x=0,f=1; 16 char ch; 17 ch=xx; 18 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=xx;} 19 while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=xx;} 20 return x*f; 21 } 22 intt a[10020]; 23 intt dp[3][5001]; 24 intt f[3][5001]; 25 int b[10000]; 26 intt sum[10000]; 27 intt ansx=0; 28 int numz=0; 29 int main() 30 { 31 int k=0; 32 n=read();m=read(); 33 for(int i=1;i<=n;i++) 34 {a[i]=read();b[i]=k;if(a[i]>0)numz++,ansx+=a[i],k=i;sum[i]=sum[i-1]+a[i];} 35 if(m>=numz){cout<<ansx<<endl;return 0;} 36 for(int i=1;i<=m;i++) 37 { 38 for(int u=1;u<=n;u++) 39 { 40 f[2][u]=max(dp[1][u-1]+a[u],f[2][u-1]+a[u]); 41 //if(a[u]>0) 42 //dp[2][u]=max(dp[1][u-1]+a[u],dp[2][b[u]]+sum[u]-sum[b[u]]); 43 dp[2][u]=max(f[2][u],dp[2][u-1]); 44 } 45 for(int u=1;u<=n;u++) 46 dp[1][u]=dp[2][u],f[1][u]=f[2][u]; 47 } 48 cout<<dp[1][n]<<endl; 49 return 0; 50 }
D - 树的距离之和
给定一棵无根树,假设它有n个节点,节点编号从1到n, 求任意两点之间的距离(最短路径)之和。Input第一行包含一个正整数n (n <= 100000),表示节点个数。
后面(n - 1)行,每行两个整数表示树的边。Output每行一个整数,第i(i = 1,2,...n)行表示所有节点到第i个点的距离之和。Sample Input
4 1 2 3 2 4 2
Sample Output
5 3 5 5
我们分析一下,对任意点的距离其实=e【i】.v*经过e【i】的次数;所以我们可以以边为单位来解决这个问题;
那么当根节点顺着边转移的时候,记次边原本被经过了x次,那么现在就变成了n-x次;而别的边是不变的;
所以我们只需要先去一个点来建一颗书,然后再递推出来答案就好了;
记得用longlong;
1 #include<iostream> 2 #include<cstring> 3 #define intt long long 4 using namespace std; 5 int read() 6 { 7 int x=0,f=1; 8 char ch; 9 ch=getchar(); 10 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} 11 while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();} 12 return x*f; 13 } 14 struct {int v,next,y,xxx;}e[1000000]; 15 int lin[1000000]; 16 int len=0; 17 intt n; 18 intt ans=0; 19 intt ansx[1000000]={}; 20 int init(int x,int y,int v) 21 {e[++len].y=y;e[len].v=v;e[len].next=lin[x];lin[x]=len;e[len].xxx=0;} 22 struct sss{intt vis,v;}; 23 int dfs(int x,int f,int vv) 24 { 25 int viss=0; 26 for(int i=lin[x];i;i=e[i].next) 27 { 28 int y=e[i].y; 29 if(y==f)continue; 30 ans+=vv+e[i].v; 31 e[i].xxx=dfs(y,x,vv+e[i].v); 32 viss+=e[i].xxx; 33 } 34 return viss+1; 35 } 36 void dfsx(int x,int f) 37 { 38 for(int i=lin[x];i;i=e[i].next) 39 { 40 int y=e[i].y; 41 if(y==f)continue; 42 int w=n-e[i].xxx; 43 ansx[y]=ansx[x]+(w-e[i].xxx)*e[i].v; 44 dfsx(y,x); 45 } 46 return ; 47 } 48 void initx() 49 { 50 n=read(); 51 //cout<<n<<endl; 52 for(int i=1;i<=n-1;i++) 53 { 54 int x=read(); 55 int y=read(); 56 init(x,y,1);init(y,x,1); 57 } 58 dfs(1,0,0); 59 ansx[1]=ans; 60 dfsx(1,0); 61 } 62 int main() 63 { 64 initx(); 65 for(int i=1;i<=n;i++) 66 { 67 cout<<ansx[i]<<endl; 68 } 69 return 0; 70 }