T1:修建牛棚
看
看
数
据
范
围
就
知
道
一
定
是
O
(
n
)
的
,
仔
细
观
察
发
现
最
小
值
肯
定
是
关
键
点
取
中
位
数
的
时
候
看看数据范围就知道一定是O(n)的,仔细观察发现最小值肯定是关键点取中位数的时候
看看数据范围就知道一定是O(n)的,仔细观察发现最小值肯定是关键点取中位数的时候
分
奇
偶
讨
论
一
下
中
位
数
在
哪
就
行
了
分奇偶讨论一下中位数在哪就行了
分奇偶讨论一下中位数在哪就行了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll ans=0;
int n;
ll x[N],y[N];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&x[i],&y[i]);
}
if(n&1)
{
ll sum1,sum2;
sort(x+1,x+n+1);
int ansn=(n+1)/2;
sum1=0,sum2=0;
for(int i=1;i<ansn;i++){
sum1=1ll*(sum1+x[i]);
}
ans=1ll*(ans+1ll*(ansn-1)*x[ansn]-sum1);
for(int i=ansn+1;i<=n;i++){
sum2=1ll*(sum2+x[i]);
}
ans=1ll*(ans+sum2-1ll*(ansn-1)*x[ansn]);
sort(y+1,y+n+1);
sum1=0,sum2=0;
for(int i=1;i<ansn;i++){
sum1=1ll*(sum1+y[i]);
}
ans=1ll*(ans+1ll*(ansn-1)*y[ansn]-sum1);
for(int i=ansn+1;i<=n;i++){
sum2=1ll*(sum2+y[i]);
}
ans=1ll*(ans+sum2-1ll*(ansn-1)*y[ansn]);
}
if((n%2==0)){
int ansn=n/2;
ll sum1=0,sum2=0;
sort(x+1,x+n+1);
for(int i=1;i<ansn;i++){
sum1=1ll*(sum1+x[i]);
}
ans=1ll*(ans+1ll*(ansn-1)*x[ansn]-sum1);
for(int i=ansn+1;i<=n;i++){
sum2=1ll*(sum2+x[i]);
}
ans=1ll*(ans+sum2-1ll*(ansn)*x[ansn]);
sum1=0,sum2=0;
sort(y+1,y+n+1);
for(int i=1;i<ansn;i++){
sum1=1ll*(sum1+y[i]);
}
ans=1ll*(ans+1ll*(ansn-1)*y[ansn]-sum1);
for(int i=ansn+1;i<=n;i++){
sum2=1ll*(sum2+y[i]);
}
ans=1ll*(ans+sum2-1ll*(ansn)*y[ansn]);
}
printf("%lld",ans);
}
T2:卖奶牛
看
看
数
据
范
围
,
先
想
到
的
就
是
d
p
了
,
d
p
[
s
]
[
j
]
[
k
]
表
示
s
子
树
中
最
大
值
为
j
,
最
小
值
为
k
的
方
案
数
,
但
始
终
不
知
道
怎
么
合
并
,
更
不
用
说
d
p
优
化
了
看看数据范围,先想到的就是dp了,dp[s][j][k]表示s子树中最大值为j,最小值为k的方案数,但始终不知道怎么合并,更不用说dp优化了
看看数据范围,先想到的就是dp了,dp[s][j][k]表示s子树中最大值为j,最小值为k的方案数,但始终不知道怎么合并,更不用说dp优化了
上
述
算
法
的
瓶
颈
在
于
最
大
值
和
最
小
值
都
不
知
道
,
所
以
不
妨
钦
定
一
个
最
大
值
,
为
了
保
证
不
重
复
,
我
们
只
算
大
的
包
含
小
的
方
案
,
相
同
则
只
算
编
号
较
小
的
方
案
上述算法的瓶颈在于最大值和最小值都不知道,所以不妨钦定一个最大值,为了保证不重复,我们只算大的包含小的方案,相同则只算编号较小的方案
上述算法的瓶颈在于最大值和最小值都不知道,所以不妨钦定一个最大值,为了保证不重复,我们只算大的包含小的方案,相同则只算编号较小的方案
即
先
对
v
[
i
]
从
大
到
小
排
序
,
对
于
每
个
i
,
做
一
次
d
f
s
(
即
钦
定
i
要
选
)
,
看
看
有
多
少
种
方
案
,
一
旦
遇
到
v
[
i
]
−
最
小
值
比
d
大
的
就
返
回
即先对v[i]从大到小排序,对于每个i,做一次dfs(即钦定i要选),看看有多少种方案,一旦遇到v[i]-最小值比d大的就返回
即先对v[i]从大到小排序,对于每个i,做一次dfs(即钦定i要选),看看有多少种方案,一旦遇到v[i]−最小值比d大的就返回
注意点:v[i]相同时会重复计算,要特判
#include<bits/stdc++.h>
using namespace std;
const int N=2010,mod=1e9+7;
int n,d,fa[N],fv[N];
int cnt=0,head[N];
struct node1{
int v,id;
}q1[N];
struct edge{
int link,v;
}q[N<<1];
void put(int x,int y){
q[++cnt].v=y;
q[cnt].link=head[x];
head[x]=cnt;
}
bool cmp(node1 x,node1 y){
return x.v>y.v;
}
void dfs(int s,int fath){
for(int i=head[s];i;i=q[i].link){
int v=q[i].v;
if(v==fath) continue;
fa[v]=s;
dfs(v,s);
}
}
int mx,sum[N],hd;//
void solve(int rt,int fath){
sum[rt]=1;
for(int i=head[rt];i;i=q[i].link){
int v=q[i].v;
if(v==fath) continue;
if(mx-fv[v]>d||fv[v]>mx||(fv[v]==mx&&v<hd)) continue;//mx-fv[c]>d是判断题目条件,f[v]>mx,(f[v]==mx&&v<hd)是判重
solve(v,rt);
sum[rt]=1ll*((sum[v]+1)%mod)*sum[rt]%mod;
}
}
int main(){
scanf("%d%d",&n,&d);
for(int i=1;i<=n;i++){
scanf("%d",&q1[i].v);
fv[i]=q1[i].v;
q1[i].id=i;
}
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
put(u,v),put(v,u);
sort(q1+1,q1+n+1,cmp);
dfs(q1[1].id,0);
int ans=0;
for(int i=1;i<=n;i++){
int rt=q1[i].id;
mx=q1[i].v;
hd=rt;
solve(rt,0);
ans=1ll*(ans+sum[rt])%mod;
}
printf("%d",ans);
}
T3:3D农场
上
来
一
看
便
是
最
小
生
成
树
,
但
是
无
论
怎
么
调
精
度
都
还
是
不
对
上来一看便是最小生成树,但是无论怎么调精度都还是不对
上来一看便是最小生成树,但是无论怎么调精度都还是不对
其
实
∑
c
o
s
t
[
i
]
[
j
]
∑
d
i
s
[
i
]
[
j
]
,
(
其
中
d
i
s
表
第
i
个
点
与
第
j
个
点
连
边
的
距
离
,
c
o
s
t
表
花
费
)
,
像
这
种
带
分
母
的
式
子
,
其
实
最
好
用
0
/
1
分
数
规
划
,
即
二
分
出
一
个
值
,
判
断
是
否
合
法
其实\frac{\sum cost[i][j]}{\sum dis[i][j]},(其中dis表第i个点与第j个点连边的距离,cost表花费),像这种带分母的式子,其实最好用0/1分数规划,即二分出一个值,判断是否合法
其实∑dis[i][j]∑cost[i][j],(其中dis表第i个点与第j个点连边的距离,cost表花费),像这种带分母的式子,其实最好用0/1分数规划,即二分出一个值,判断是否合法
但
出
题
人
专
门
卡
了
二
分
,
要
用
d
i
n
k
e
l
b
a
c
h
但出题人专门卡了二分,要用dinkelbach
但出题人专门卡了二分,要用dinkelbach