3.31省选模拟
很久以后,还会是我一个人,站在风里,听着自己的心事
\(5.20k\)提交祭
\(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\)
毒瘤数据结构,待补