3.31省選模擬
阿新 • • 發佈:2022-03-31
\(T1\)
轉化題意,恰好取出\(k\)條鏈,使得權值儘可能大
首先貪心的想,每次都選出來最大的即可,然後這樣顯然不能保證最優吧
首先選一個,肯定是要選最大的,那麼我們考慮這次操作可能對下次產生影響
我們第二次選,可能需要撤銷一部分第一步的操作,然後選出一條最長鏈
考慮正確性,我們要假設目前存在更優的選擇選另一條鏈,那還是表示加上一個最大的權值,那麼我們這麼選的話,肯定能選出來
本質是就是反悔貪心吧,模擬費用流的過程
發現,我對於貪心的證明一直都不是很容易理解,或許思維過於僵化了
當然這道題可以\(wqs\)二分,至於凸性的話,還有種證明方法,如果能把模型轉化為費用流形式就滿足凸性
#include<bits/stdc++.h> #define INF 2147483647 #define MAXN 200005 using namespace std; vector<int>lu[MAXN]; vector<pair<int,int> >rd[MAXN]; int dp1[MAXN],dp2[MAXN],val[MAXN],nxt1[MAXN],nxt2[MAXN]; int n,k,Ans; void dfs_pre(int now,int fa) { for(int i=0;i<rd[now].size();i++) { int y=rd[now][i].first; if(y==fa) continue; val[y]=rd[now][i].second; lu[now].push_back(y); dfs_pre(y,now); } } void dfs(int now) { for(int i=0;i<lu[now].size();i++) { int y=lu[now][i]; dfs(y); if(dp1[y]+val[y]>dp1[now]) { nxt2[now]=nxt1[now]; dp2[now]=dp1[now]; nxt1[now]=y; dp1[now]=dp1[y]+val[y]; } else if(dp1[y]+val[y]>dp2[now]) { nxt2[now]=y; dp2[now]=dp1[y]+val[y]; } } // cout<<"now: "<<now<<" "<<dp2[now]<<" "<<nxt2[now]<<endl; } int main() { freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); scanf("%d%d",&n,&k); for(int i=1,u,v,w;i<n;i++) { scanf("%d%d%d",&u,&v,&w); rd[u].push_back(make_pair(v,w)); rd[v].push_back(make_pair(u,w)); } dfs_pre(1,1); for(int i=1;i<=k;i++) { memset(dp1,0,sizeof(dp1)); memset(dp2,0,sizeof(dp2)); memset(nxt1,0,sizeof(nxt1)); memset(nxt2,0,sizeof(nxt2)); dfs(1); int Max=-INF,rt; for(int j=1;j<=n;j++) { if(Max<dp1[j]+dp2[j]) { Max=dp1[j]+dp2[j]; rt=j; } } // cout<<"Max: "<<Max<<"\n"; Ans+=Max; int now=rt; while(nxt1[now]) { now=nxt1[now]; val[now]*=-1; } now=nxt2[rt]; // cout<<"nxt2: "<<now<<endl; while(now) { val[now]*=-1;now=nxt1[now]; // cout<<"val: "<<val[now]<<"\n"; } } cout<<Ans<<"\n"; }
\(T2\)
推式子的\(ppt\)有\(87\)頁,很好,那咱們開推
(笑)大概要不少時間呢
\(sub_1:n<=10\)
考慮列舉所有二叉樹形態,沒想到題解的辦法,吃飯的時候糊了一個,由於二叉樹可以二進位制表示,那麼列舉所有的二進位制狀態就好了,複雜度\(O(2^nn),\)可以打出前十項的表
\(Sub_2\)
推式子
#define Eternal_Battle ZXK #include<bits/stdc++.h> #define mod 1000000007 #define int long long #define MAXN 2000005 using namespace std; const int up=259; inline int re() { int x = 0, p = 1; char ch = getchar(); while(ch > '9' || ch < '0') {if(ch == '-') p = -1; ch = getchar();} while(ch <= '9' and ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();} return x * p; } int p,inv[MAXN],pw[MAXN],dw[MAXN],*C=inv,n,T; int iv3,iv6,iv15,iv120,c1,c2; void Init() { inv[1]=1; for(int i=2;i<MAXN;i++) inv[i]=(-inv[p%i])*(p/i)%p; iv3=inv[3]; iv6=inv[6]; iv15=inv[15]; iv120=inv[120]; c1=2*iv3%p;c2=5*inv[12]%p; for(int i=2;i<MAXN;i++) { inv[i]=inv[i-1]*inv[i]%p; } pw[0]=1; for(int i=1;i<MAXN;i++) { pw[i]=pw[i-1]*4%p; dw[i]=(i-1)*i%p; } for(int i=1,j=1,fac=1;i<MAXN;i++,j+=2) { C[i]=inv[i]*inv[i]%p*(fac=fac*j%p*(j+1)%p)%p; } } void Input() { p=re(),T=re(); } void Eternal_Battle() { while(T--) { int k=re(),n=re(); if(k==1) { if(n<3) { printf("0\n"); continue; } int now=((2*n-4)*pw[n-3]%p+iv6*dw[n-1]%p*C[n-1]-iv3*dw[n-2]%p*C[n-2])%p; now=(now+p)%p; printf("%lld\n",now); } else { if(n<3) { printf("0\n"); continue; } int now=((2*n*pw[n-3]+iv120*dw[n]%p*C[n])%p*(n-2)+(iv15*(n-3)+c2)%p*dw[n-1]%p*C[n-1]+((iv15*(n-4)+c1)%p*dw[n-2]+n-2)%p*2*C[n-2]%p)%p; now=(now+p)%p; printf("%lld\n",now); } } } signed main() { freopen("contact.in","r",stdin); freopen("contact.out","w",stdout); Input();Init(); Eternal_Battle(); return 0; }
\(T3\)
毒瘤資料結構,待補