下发文件和题解
T1 接力比赛
既然要求取小白与小黑班级总 值相等时总 的最大值,那么这就可以转化为最简单的 背包问题.
设 和 分别表示小黑和小白班级中 值为 时 的最大值.
枚举 获得 和 ,那么转移显然:
然后扫一遍查询一下和的最大值即可.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define sort random_shuffle // Shiyiming的梗
#define rll rg ll
#define maxn 1000001
using namespace std;
static inline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f?-x:x;
}
static inline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|48);
}
struct node
{
ll w,v;
}a[maxn],b[maxn];
ll n,m,mx,mmx,ans;
ll dp[2][maxn];
int main()
{
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
memset(dp,-0x3f,sizeof(dp));
n=read();m=read();
for(rll i=1;i<=n;i++) a[i].w=read(),a[i].v=read();
for(rll i=1;i<=m;i++) b[i].w=read(),b[i].v=read();
sort(a+1,a+n+1);sort(b+1,b+m+1);
mx=dp[0][0]=0;
for(rll i=1;i<=n;i++)
for(rll j=mx;j+1;j--)
{
if(dp[0][j+a[i].w]<dp[0][j]+a[i].v)
{
dp[0][j+a[i].w]=dp[0][j]+a[i].v;
mx=max(mx,j+a[i].w);
}
}
mmx=max(mmx,mx);
mx=dp[1][0]=0;
for(rll i=1;i<=m;i++)
for(rll j=mx;j+1;j--)
{
if(dp[1][j+b[i].w]<dp[1][j]+b[i].v)
{
dp[1][j+b[i].w]=dp[1][j]+b[i].v;
mx=max(mx,j+b[i].w);
}
}
mmx=max(mmx,mx);
for(rll i=1;i<=mmx;i++) if(dp[0][i]&&dp[1][i]) ans=max(ans,dp[0][i]+dp[1][i]);
write(ans);
return 0;
}
T2 树上竞技
由于按照点考虑并不好做,所以转移一下思路,按照边考虑.
对于一条边,如果它的两侧分别有 和 个点,我们可以设 ,那么最后的汇聚点一定是在 这个方向.
所以,可以设一条边的两侧分别有 和 个点,那么我们要求的答案即为:
.为什么要取min?
因为我们要求的是最小代价,所以要在左子树和右子树中寻找价值最小的点数.
然后就是把 拆开:
.m为偶数时的情况,可以通过一遍循环求出.
对于前面的部分,令 ,那么 .令 ,答案即为 .
对于 ,其实它的意义是从一个有 个物品的架子拿 个物品,前面 个物品中拿了 个的方案数.
如果要从 变成 ,发现答案变少的部分就是前面 个选了 个,而 也被选中了,只有这种情况会被 计算而不会被 计算.那么左右两种情况乘起来就是 .即:
.点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 2000001
#define mod 1000000007
using namespace std;
static inline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f?-x:x;
}
static inline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|48);
}
ll n,m,k,ans;
vector<ll> g[maxn];
ll s[maxn],jc[maxn],ny[maxn],G[maxn];
bool fl[maxn];
static inline void dfs(rll x,rll fa)
{
s[x]=1;
for(rll i=0;i<g[x].size();i++)
{
rll to=g[x][i];if(to==fa) continue;
dfs(to,x);s[x]+=s[to];
}
}
static inline ll ksm(rll a,rll b)
{
rll ans=1;a%=mod;
for(rll i=b;i;i>>=1)
{
if(i&1) ans=ans*a%mod;
a=a*a%mod;
}
return ans;
}
static inline ll C(rll n,rll m)
{
if(n<m) return 0;
return jc[n]*ny[m]%mod*ny[n-m]%mod;
}
int main()
{
freopen("meeting.in","r",stdin);
freopen("meeting.out","w",stdout);
jc[0]=ny[0]=1;for(rll i=1;i<maxn;i++) jc[i]=jc[i-1]*i%mod;
ny[maxn-1]=ksm(jc[maxn-1],mod-2);for(rll i=maxn-2;i;i--) ny[i]=ny[i+1]*(i+1)%mod;
n=read();m=read();if(m==1) { puts("0"); return 0; }
for(rll i=2,v;i<=n;i++) v=read(),g[i].push_back(v),g[v].push_back(i);
dfs(1,0);
if(!(m&1)) for(rll i=1;i<=n;i++) ans=(ans+C(s[i],m>>1)*((n-s[i]<0)?0:C(n-s[i],m>>1))%mod*(m>>1)%mod)%mod;
k=m-1>>1;if(k) G[1]=C(n-1,m-1);
for(rll i=1;i<=n;i++) G[i+1]=(G[i]-((i-1<0||k-1<0)?0:C(i-1,k-1))*((n-i-1<0||m-k-1<0)?0:C(n-i-1,m-k-1))%mod+mod)%mod;
for(rll i=1;i<=n;i++) ans=(ans+(G[s[i]]*s[i]%mod+G[n-s[i]]*(n-s[i])%mod)%mod)%mod;
write(ans);
return 0;
}