您的位置:首页 > 其它

51nod算法马拉松20

2016-11-28 00:06 295 查看
先写一下做出的题吧(感觉自己好弱。。。。。)

A:

拆分贡献,组合数搞一搞;

#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;i++)
#define rep2(i,k,n) for(int i=k;i>=n;i--)
using namespace std;
typedef long long ll;
const int N=2e5+7;
const int mod=1e9+7;
void upd(int& x,int y){x+=y;if(x>=mod)x-=mod;}
int qpow(int a,int b){int aa=a,res=1;for(;b;b>>=1){if(b&1)res=1ll*res*aa%mod;aa=1ll*aa*aa%mod;}return res;}
int bin
,pin
,ans=0;
void init(){bin[0]=pin[0]=1;
rep(i,1,N-1)bin[i]=1ll*bin[i-1]*i%mod;
pin[N-1]=qpow(bin[N-1],mod-2);
rep2(i,N-2,1)pin[i]=1ll*pin[i+1]*(i+1)%mod;
}
int C(int x,int y){
if(y>x)return 0;
return 1ll*bin[x]*pin[x-y]%mod*pin[y]%mod;
}
struct E{
int to,next;E(int to=0,int next=0):to(to),next(next){}
}edge
;
int head
,tot=0,n,k,sz
;
void add(int x,int y){
edge[++tot]=E(y,head[x]);head[x]=tot;
edge[++tot]=E(x,head[y]);head[y]=tot;
}
void dfs(int x,int fa){
sz[x]=1;
for(int i=head[x];i;i=edge[i].next){
int to=edge[i].to;
if(to!=fa){
dfs(to,x);
sz[x]+=sz[to];
upd(ans,C(n,k));
upd(ans,mod-C(sz[to],k));
upd(ans,mod-C(n-sz[to],k));
}
}
}
int main(){
init();
scanf("%d%d",&n,&k);
rep(i,1,n-1){
int x,y;scanf("%d%d",&x,&y);
add(x,y);
}dfs(1,0);
printf("%d\n",ans);
}


B:

一开始看到这题思如泉涌,但没有一种靠谱……..

好长时间之后,通过数形结合(乱涂乱画)发现:

差分就行了……

说明了数形结合(乱涂乱画)的重要性;

#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;i++)
#define rep2(i,k,n) for(int i=k;i>=n;i--)
using namespace std;
void sc(int& x){x=0;char c=getchar();while(c>'9' || c<'0')c=getchar();
for(;c>='0' && c<='9';c=getchar())x=x*10+c-'0';
}
typedef int ll;
const int N=1e6+7;
vector<int> tu
;
int a
,n,mx=0,stk
,top;
ll cha
,ans=0;
void solve(int x){top=tu[x].size();
rep(i,0,top-1)stk[i+1]=tu[x][i];
ll sum=0;
rep(i,2,top){
sum+=(i-1)*(stk[i]-stk[i-1])+1;
cha[stk[i]+1]-=(sum+i-1);
cha[stk[i]+2]+=(sum-i+1);
}
sum=0;
rep2(i,top-1,1){
sum+=(top-i)*(stk[i+1]-stk[i])+1;
cha[stk[i]]+=(top-i-sum);
cha[stk[i]+1]+=(top-i+sum);
}
}
int main(){
sc(n);
rep(i,1,n){
sc(a[i]);
mx=max(mx,a[i]);
tu[a[i]].push_back(i);
}
rep(i,1,mx)
if(tu[i].size()>1)
solve(i);
rep(i,1,n)cha[i]+=cha[i-1];
rep(i,1,n)cha[i]+=cha[i-1];
rep(i,1,n){
ans+=1ll*cha[i]*a[i];
}
printf("%u\n",ans);
return 0;
}


D:

一定要对每一道题认真刨析。

权函数凸性满足,四边形不等式满足;

放在序列上就是裸利用矩阵凸单调性,那么树上怎么做呢?

一样做!维护决策树就可以了,然后发现真正的树的结构也不那么重要了;

#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;i++)
#define rep2(i,k,n) for(int i=k;i>=n;i--)
using namespace std;
typedef long long ll;
const int N=1e5+7;
const int inf=0x3f3f3f3f;
const ll Inf=0x3f3f3f3f3f3f3f3full;
ll f
,a
,ans=Inf;
int son
,fa
,n,p,be
,who
;
struct E{
int to,next;E(int to=0,int next=0):to(to),next(next){}
}edge[N<<1];
int head
,tot=0;
void add(int x,int y){
edge[++tot]=E(y,head[x]);head[x]=tot;
}
ll g(int j,int i){
if(pow(i-j,p)>Inf)return Inf;
return f[j]+1ll*pow(i-j,p)+a[i];
}
int vs(int x,int now){
int l=x+1,r=n+1;
while(l<r){
int mid=(l+r)>>1;
if(g(x,mid)<=g(now,mid))r=mid;
else l=mid+1;
}
return l;
}
void dp(int x,int now){
while(be[son[now]]<=x)now=son[now];
who[x]=now;
if(x>1)f[x]=g(now,x);
else f[x]=a[x];
for(;fa[x] && g(fa[x],max(be[fa[x]],x+1))>=g(x,max(be[fa[x]],x+1));fa[x]=fa[fa[x]],now=min(now,fa[x]));
int cx=son[fa[x]];
son[fa[x]]=x;
be[x]=vs(x,fa[x]);

for(int i=head[x];i;i=edge[i].next){
int v=edge[i].to;
dp(v,now);
}
son[fa[x]]=cx;

if(!head[x])ans=min(ans,f[x]-a[x]);
}
int main(){
scanf("%d%d",&n,&p);
rep(i,1,n){
scanf("%lld%d",&a[i],&fa[i]);
add(fa[i],i);
}be[0]=inf,f[0]=Inf;
dp(1,0);
printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  马拉松 数学 dp 差分