好啊,好啊,我又一次爆掉了(我都不意外了)
比完赛T1,T2直接A,听讲后T3又A,于是改完了题。
T1:联合权值
对于一个点,和它距离为2的点只有爷爷和亲生兄弟,所以
a
n
s
=
∑
(
∑
b
r
o
t
h
e
r
i
+
2
∗
g
r
a
n
d
f
a
t
h
e
r
i
)
∗
a
i
ans=\sum (\sum brother_i+2*grandfather_i)*a_i
ans=∑(∑brotheri+2∗grandfatheri)∗ai
代码(与上面公式不同,本质差不多)
#include<bits/stdc++.h>
#define rg register
#define mod 10007
#define Fu(i,a,b) for(rg int i=(a);i<=(b);i++)
#define Fd(i,a,b) for(rg int i=(a);i>=(b);i--)
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
using namespace std;
int n,a[200005],fa[200005],ans,maxn;
int next[400005],first[400005],to[400005],tot;
void add(int u,int v){
next[++tot]=first[u];first[u]=tot;to[tot]=v;
next[++tot]=first[v];first[v]=tot;to[tot]=u;
}
void dfs(int o,int from){
int sum=0,ma=0;
for(int i=first[o];i;i=next[i]){
int v=to[i];
if(v==from) continue;
ans=(ans+a[v]*a[fa[o]]%mod+a[v]*sum%mod)%mod;
maxn=max(maxn,max(a[v]*a[fa[o]],a[v]*ma));
sum=(sum+a[v])%mod;
ma=max(ma,a[v]);
fa[v]=o;
dfs(v,o);
}
}
int main(){
scanf("%d",&n);
Fu(i,2,n){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
Fu(i,1,n) scanf("%d",&a[i]);
dfs(1,0);
printf("%d %d",maxn,ans*2%mod);
return 0;
}
T2:寻找道路
先dfs判断哪些点能走,再跑一遍SPFA(其实只用跑bfs,因为边的权值为1)
代码
#include<bits/stdc++.h>
#define rg register
#define Fu(i,a,b) for(rg int i=(a);i<=(b);i++)
#define Fd(i,a,b) for(rg int i=(a);i>=(b);i--)
using namespace std;
int n,m,s,t;
int next[200005],first[200005],to[200005],tot;
void add(int u,int v){
next[++tot]=first[u];first[u]=tot;to[tot]=v;
}
int next1[200005],first1[200005],to1[200005],tot1;
void add1(int u,int v){
next1[++tot1]=first1[u];first1[u]=tot1;to1[tot1]=v;
}
int js1[10005],js[10005],bj[10005],dis[10005],q[100005],l,r=1;
void dfs(int o){
js1[o]=1;
for(int i=first1[o];i;i=next1[i]){
if(js1[to1[i]]==0){
dfs(to1[i]);
}
}
}
int main(){
scanf("%d%d",&n,&m);
Fu(i,1,m){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add1(v,u);
}
scanf("%d%d",&s,&t);
dfs(t);
Fu(j,1,n){
if(js1[j]==0){
js[j]=1;
for(int i=first1[j];i;i=next1[i]) js[to1[i]]=1;
}
}
Fu(i,1,n) dis[i]=0x7fffffff;
bj[s]=1,dis[s]=0,q[1]=s;
while(l<r){
l++;
int u=q[l],bz=0;
bj[u]=0;
if(bz==1) continue;
for(int i=first[u];i;i=next[i]){
int v=to[i];
if(dis[v]>dis[u]+1&&js[v]==0){
dis[v]=dis[u]+1;
if(bj[v]==0){
q[++r]=v;
bj[v]=1;
}
}
}
}
if(dis[t]==0x7fffffff) printf("-1");
else printf("%d",dis[t]);
return 0;
}
T3:飞扬的小鸟
70分DP
设
f
f
fi,j为在
(
i
,
j
)
(i,j)
(i,j)位置的最小点击数,
转移是
f
f
fi,j=min(
f
f
fi-1,j+y ,
f
f
fi-1,j-k*x +k)
(x为上升,y为下降,k为上升次数)
时间复杂度:
O
(
n
m
2
)
O(nm^2)
O(nm2)
100分DP
设
f
f
fi,j为在
(
i
,
j
)
(i,j)
(i,j)位置的最小点击数,
设
g
g
gj为在
(
i
+
1
,
j
)
(i+1,j)
(i+1,j)位置的最小点击数,
转移是
g
g
gj+x=
g
g
gj+1
f
f
fi+1,j-y=
f
f
fi,j
f
f
fi+1,j+x=
g
g
gj+1
这里有完全背包的思想
时间复杂度:
O
(
n
m
)
O(nm)
O(nm)
代码
#include<bits/stdc++.h>
#define rg register
#define Fu(i,a,b) for(rg int i=(a);i<=(b);i++)
#define Fd(i,a,b) for(rg int i=(a);i>=(b);i--)
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
using namespace std;
int n,m,k,x[10005],y[10005],tot;
int f[10005][1005],g[1005];
int p,bj[10005],l[10005],h[10005];
int minx=0x7fffffff;
int main(){
scanf("%d%d%d",&n,&m,&k);
Fu(i,0,n-1) scanf("%d%d",&x[i],&y[i]);
Fu(i,1,k){
scanf("%d",&p);
scanf("%d%d",&l[p],&h[p]);
bj[p]=1;
}
Fu(i,0,n) if(l[i]==0&&h[i]==0) l[i]=0,h[i]=m+1;
Fu(i,0,n-1){
tot+=bj[i];
Fu(j,0,m)g[j]=f[i][j],f[i+1][j]=0x7ffffff;
Fu(j,0,m)g[min(j+x[i],m)]=min(g[j]+1,g[min(j+x[i],m)]);
Fu(j,0,m){
int u=j-y[i];
if(u>l[i+1]&&u<h[i+1]) f[i+1][u]=min(f[i+1][u],f[i][j]);
u=min(m,j+x[i]);
if(u>l[i+1]&&u<h[i+1]) f[i+1][u]=min(f[i+1][u],g[j]+1);
}
int mi=0x7ffffff;
Fu(j,0,m){
mi=min(mi,f[i+1][j]);
}
if(mi==0x7ffffff){
printf("0\n%d",tot);
return 0;
}
}
int mi=0x7ffffff;
Fu(i,1,m) mi=min(mi,f[n][i]);
printf("1\n%d",mi);
return 0;
}
总结
又是打挂的一天
实力已达230
好啊,好啊,我又一次爆掉了(我都不意外了)
比完赛T1,T2直接A,听讲后T3又A,于是改完了题。