D-Bovine Small Tree
Beginning spit myself:
This question has not been made (it's too delicious). When you do this, you think a lot of ways. Finally, you feel it is difficult to achieve it. After you finish, you will see the video explanation.
It's obvious that this is a DP practice, but I don't have any personal thoughts about the transfer of dp. My DP is too weak, so I wrote a memory search.
ll f1(int u,int g) { if(u==0)return 0; if(dp[u])return dp[u]; for(int i=g;i>=1;--i) { k=0; // cout<<u<<" "<<f[i].s<<" "<<i<<endl; if(u<f[i].s)continue; ll v=(ll)u; ll z=v/f[i].s; ll ans1=z*f[i].x; k+=v; ans1+=f1(v%f[i].s,i-1); if(ans1>dp[u])dp[u]=ans1,ans2=k; // cout<<u<<" "<<dp[u]<<" "<<i<<endl; } return dp[u]; }
u is the degree of the tree, g is the layer, here I am sorted, in fact, it doesn't matter if I don't sort, unfortunately, the last sample is not there.. Too bad.
Then I find that there are actually some limitations, and then I don't know what to do.
Then think about a wrong dp and wait until you see the solution.
Practice:
If n points form a tree, that is:
The total degree of 1.n points is 2*n-2
2. Range of each point [1, n-1]
A key point is that if each point is assigned a degree, the remaining n-2 degrees are allocated freely, I will certainly refute, I can only convince myself if I can't find any refute. According to the DFS order of the tree, you can know that the degree of a point is the number of times + 1 that occur in the Prufer order, so I think this conclusion should be correct.
How do I transfer it later? My wrong dp thought was:Add a new point and an edge to the current tree, and then change the degree + 1 of a point on the tree, and add a point of 1 degree. In fact, dp is difficult to start. For example, the tree with 4 nodes formed before has several total shapes. Then add a point you want to make sure that every point + degree in each shape is calculated once, which is difficult to represent and tle
We know the degree range of a point before, so long as you enumerate the degrees selected for each point, you can choose the maximum answer. Actually, you can see that this is a backpack problem, i.e. the 2n-2 backpack size, the maximum value of n items, and 1-n-1 choice for each item (a bit of a problem)In fact, the backpack problem allows us to choose or not for each item, but now it limits the selection of at least one item, so the key mentioned earlier works. We can assume that there is already one degree for each point, and then each point can be added 0-n-2 degrees, which is equivalent to either not selecting or selecting 1-n-2, then writing two dimensions into one dimension.
//Cowdriver, after writing, can't say exactly the same, can only say no difference.
Cabbage chicken insight: I feel that the problem is how to think of him as a backpack and the degree requirements that make up a tree.
Hear this is a bit original, so do something else
P5454 [THUPC2018] Urban Metro Planning
As you can see from the above question, this is a dp question. Nonsense, what you are looking for is an enhanced version of the above question. After you get the f out in advance, it will be exactly the same as the previous question. There are more problems with output paths. However, it will not be written, the Prufer sequence and rebuilt tree will be clouded, and then you can solve the problem according to the question.
#include<bits/stdc++.h> using namespace std; typedef long long int ll; const int mod=59393; const int M=3005; int a[15]; int f[M*2]; int pre[M*2]; ll dp[M*2]; int map1[M][M]; int fa[M]; int ans=0; int d[M]; int vis1[M]; int n,k; void F() { for(int i=1;i<=n-1;++i) { for(int j=k;j>=0;--j) { f[i]=(f[i]*i+a[j])%mod; } // cout<<f[i]<<endl; } } int main() { cin>>n>>k; for(int i=0;i<=k;++i)cin>>a[i]; F(); if(n==1) { cout<<"0"; return 0; } else if(n==2) { cout<<(2*f[1])%mod; return 0; } memset(dp,128,sizeof(dp)); dp[0]=0; for(int i=1;i<=n-1;++i) { for(int j=i;j<=n-2;++j) { ll z=dp[j-i]+1ll*f[i+1]-1ll*f[1]; if(z>dp[j]) { dp[j]=z; pre[j]=j-i; } } } dp[n-2]=dp[n-2]+1ll*(n*f[1]); for(int i=n-2;i;i=pre[i]) { d[++ans]=i-pre[i]+1; } int j=2; for(int i=1;i<=ans;++i) { for(;j<=ans;++j) { if(d[i]&&d[j]) { fa[j]=i; d[j]--; d[i]--; } else break; } } int l=1; int i=ans+1; while(i<=n) { while(fa[i])++i; while(l<=ans&&!d[l])l++; d[l]--; fa[i]=l; //cout<<i<<" "<<l<<endl; } cout<<n-1<<" "<<dp[n-2]<<endl; for(i=2;i<=n;++i) { cout<<i<<" "<<fa[i]<<endl; } }
Found blogging affects my moustache speed, have time to moustache again