NOIP2018普及&提高题解

时间:2022-03-02 00:39:29

第一次考$NOIP$的我已经自闭了


$CCF$告诉我们了一件事情,要对自己写的程序有信仰,相信$CCF$的数据是水的

普及组:

分数:$100+100+30+100=330$

$1.titile$:

$cin$,$scanf$都试了试,却没有$A$掉第二个样例,最后$getchar()$$5$次$A$掉了

考场上加了一句读掉换行就停止,要是不加就会$WA$的很惨

$5$次$getchar()$,遇见换行停止

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
int ans=,tot;
int main(){
freopen("title.in","r",stdin);
freopen("title.out","w",stdout);
while(tot<=){
char str=getchar();
if(int(str)==) break;
if((str>=''&&str<='')||(str>='a'&&str<='z')||(str>='A'&&str<='Z')) ans++;
tot++;
}
cout<<ans;
return ;
}

$2.fight$:

自闭了,被卡精度,简单的$O(n)$暴力。

$update$:$CCF$的数据是真水啊,好像开$int$过掉了

直接暴力枚举加入之后的*就行

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define int long long
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
int m,p1,s1,s2,pos,n,a[],sum1,sum2,minn,inf=<<-;
signed main(){
freopen("fight.in","r",stdin);
freopen("fight.out","w",stdout);
n=read();
for(int i=;i<=n;i++) a[i]=read();
m=read(),p1=read(),s1=read(),s2=read();
a[p1]+=s1;
for(int i=;i<m;i++) sum1+=(m-i)*a[i];
for(int i=m+;i<=n;i++) sum2+=(i-m)*a[i];
minn=abs(sum2-sum1);
pos=m;
for(int i=;i<=n;i++){
int ans1=sum1,ans2=sum2;
if(i<m) ans1+=(m-i)*s2;
if(i>m) ans2+=(i-m)*s2;
int k=abs(ans1-ans2);
if(k<minn){minn=k,pos=i;}
}
cout<<pos;
return ;
}

$3.bus$:

观察$n$与$m$的范围,应该是一个二维$dp$,所以我们令$dp(i,j)$表示时间为$a[i]+j$,第$i$个人上车的等候总和,所以可以分两种情况考虑

1.当第$i$个人与第$i-1$个人不坐同一辆车时,则$dp(i,j)=max(dp(i,j),dp(i-1,k)+j)$

2.当第$i$个人愿意去并且与第$i-1$个人坐同一辆车则$dp(i,j)=max(dp(i,j),dp(i-1,k)+j)$

主要是对两种情况的判断

详情见代码

考场上其实写的是$dp(i,j)$为第$i$个人,当前时间为$j$且第$i$个人上车的等车情况,最后挂了,时间巨大

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
const int MAXN=;
const int MAXM=;
int N,M,A[MAXN],f[MAXN][MAXM],INF=INT_MAX;
int main(){
freopen("bus.in","r",stdin);
freopen("bus.out","w",stdout);
memset(f,/,sizeof(f));
N=read(),M=read();for(int i=;i<=N;i++) A[i]=read();sort(A+,A+N+);
for(int i=;i<M;i++) f[][i]=i;
for(int i=;i<=N;i++){
for(int j=;j<*M;j++){
if(j+A[i]-A[i-]>=&&j+A[i]-A[i-]<*M) f[i][j]=f[i-][j+A[i]-A[i-]]+j;
for(int p=;p<*M;p++){
int T=j+A[i],t1=p+A[i-]+M;if(t1>T) continue;
f[i][j]=min(f[i][j],f[i-][p]+j);
}
}
}
int Minn=INF;
for(int i=;i<*M;i++) Minn=min(Minn,f[N][i]);
printf("%d\n",Minn);return ;
}

$4.tree$:

搜索。

因为树是满足条件的必须

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
const int MAXN=;
struct node{
int siz,id;
}f[MAXN];
int L[MAXN],R[MAXN],siz[MAXN],N,A[MAXN],d[MAXN],rt;
void dfs1(int u){
siz[u]=;
if(L[u]) dfs1(L[u]),siz[u]+=siz[L[u]];
if(R[u]) dfs1(R[u]),siz[u]+=siz[R[u]];
return;
}
bool cmp(node x1,node x2){return x1.siz>x2.siz;}
bool checker(int u,int v){
if(!u&&!v) return ;
if(siz[u]!=siz[v]) return ;
if(A[u]!=A[v]) return ;
return checker(L[u],R[v])&&checker(R[u],L[v]);
}
int main(){
N=read();
for(int i=;i<=N;i++) A[i]=read();
for(int i=;i<=N;i++){
L[i]=read(),R[i]=read();
if(L[i]==-) L[i]=;if(R[i]==-) R[i]=;
d[L[i]]++,d[R[i]]++;
}
for(int i=;i<=N;i++) if(!d[i]){rt=i;break;}dfs1(rt);
for(int i=;i<=N;i++) f[i].siz=siz[i],f[i].id=i;sort(f+,f+N+,cmp);
for(int i=;i<=N;i++){
int tr=f[i].id;
if(checker(L[tr],R[tr])){printf("%d\n",f[i].siz);return ;}
}return ;
}

提高组:

分数:

day1:$100+0+55=155$

day2:$100+60+44=204$

$day1+day2=359$

$1.road$

差分即可,将序列差分以后可以看成将一个位置 $+1$ ,一个位置 $-1$,直接统计 $+1$ 块即可,因为可以将 $+1$ 块与 $-1$ 块匹配。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
int cnt=;
struct node{
int l,r;
}x[];
int n,a[],sum;
signed main(){
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
n=read();
for(int i=;i<=n;i++) a[i]=read();
x[].l=;
for(int i=;i<=n;i++){
if(a[i]>a[i-]) x[cnt].r=i-,x[++cnt].l=i;
}
int minn=;
x[cnt].r=n;
for(int i=;i<=cnt;i++){
sum+=(a[x[i].l]-minn);
minn=a[x[i].r];
}
cout<<sum;
return ;
}

$2.money$

考虑$n=2$的情况入手,发现若只能取一个就必须一个是另一个的倍数,然后我们就可以大胆猜想答案的货币系统一定是其原先货币系统的子集,然后经过简单思考发现这个结论是对的。

然后就是一个十分水的背包$dp$了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return ans*f;
}
int T,a[],n,ans,M;
bool dp[];
int main()
{
freopen("money.in","r",stdin);
freopen("money.out","w",stdout);
T=read();
while(T--){
n=read();
ans=;
for(int i=;i<=n;i++) a[i]=read();
sort(a+,a+n+);
M=a[n];
memset(dp,,sizeof(dp));
dp[]=;
for(int i=;i<=n;i++){
if(!dp[a[i]]){
ans++;
for(int j=a[i];j<=M;j++) dp[j]|=dp[j-a[i]];
}
}
cout<<ans<<endl;
}
}

$3.track$

主要的思想就是选择两个子孙链上的进行合并,然后在不能合的里面选择最大的一条往上传即可。正确性显然。$multiset$ 维护一下即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<set>
#define int long long
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
const int MAXN=;
multiset<int> s[MAXN];
int n,k;
struct node{
int u,v,w,nex;
}x[MAXN<<];
int ans,l,r,head[MAXN],cnt,maxn;
void add(int u,int v,int w){
x[cnt].u=u,x[cnt].v=v,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++;
}
int dfs(int xx,int fath,int lim){
s[xx].clear();
for(int i=head[xx];i!=-;i=x[i].nex){
if(x[i].v==fath) continue;
int val=dfs(x[i].v,xx,lim)+x[i].w;
if(val>=lim) ans++;
else s[xx].insert(val);
}
int maxn=;
while(!s[xx].empty()){
if(s[xx].size()==) return max(maxn,*s[xx].begin());
multiset<int> :: iterator it=s[xx].lower_bound(lim-*s[xx].begin());
if(it==s[xx].begin()&&s[xx].count(*it)==) it++;
if(it==s[xx].end()){
maxn=max(maxn,*s[xx].begin());
s[xx].erase(s[xx].find(*s[xx].begin()));
}else{
ans++;
s[xx].erase(s[xx].find(*s[xx].begin()));
s[xx].erase(s[xx].find(*it));
}
}
return maxn;
}
bool check(int xx){
ans=;
dfs(,,xx);
return ans>=k;
}
int dis[MAXN];
void dfs1(int f,int fath){
for(int i=head[f];i!=-;i=x[i].nex){
if(x[i].v==fath) continue;
dis[x[i].v]=dis[f]+x[i].w;
dfs1(x[i].v,f);
}
return;
}
int get_dis(){
dfs1(,);
int maxn=,pos;
for(int i=;i<=n;i++){
if(dis[i]>maxn){
maxn=dis[i],pos=i;
}
}
dfs1(pos,);
maxn=;
for(int i=;i<=n;i++) maxn=max(maxn,dis[i]);
return maxn;
}
signed main(){
freopen("track.in","r",stdin);
freopen("track.out","w",stdout);
memset(head,-,sizeof(head));
n=read(),k=read();
for(int i=;i<n;i++){
int u=read(),v=read(),w=read();
add(u,v,w),add(v,u,w);
}
r=get_dis();
while(l<=r){
int mid=l+r>>;
if(check(mid)) l=mid+,maxn=max(maxn,mid);
else r=mid-;
}
cout<<maxn;
}

$4.travel$

$update$:$CCF$的数据是真水啊,好像$O(n^2\times m)$过掉了

树的做法很简单吧,当遍历到节点$i$时,继续$dfs$编号最小且此节点的父亲是$i$的,$dfs$是因为与题意相符,回溯与往下。

当是个基环树的时候,我们可以发现其实有一条边是没有做过的,就去每次暴力删边,然后将每次的字典序记录下来,最后输出最小字典序即可

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
struct node{
int u,v,nex;
}x[];
int head[];
int cnt,n,m;
void add(int u,int v){
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
int st[];
bool vis[];
int delu,delv,tot;
int da[];
int pig;
int kk[][];
int scc,cntcnt[],pos;
void dfs(int f,int fath){
if(pig==) return;
int son=;
int sry=;
while(sry<cntcnt[f]){
++sry;
pos=kk[f][sry];
if(vis[pos]) continue;
if((f==delu&&pos==delv)||(f==delv&&pos==delu)) continue;
vis[pos]=;
st[++st[]]=pos;
if(st[st[]]>da[st[]]&&pig!=){pig=;return;}
if(st[st[]]<da[st[]]){pig=;}
dfs(pos,f);
}
return;
}
struct node1{
int u,v;
}se[];
int main(){
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
memset(da,/,sizeof(da));
memset(head,-,sizeof(head));
n=read(),m=read();
for(int i=;i<=m;i++){
int u=read(),v=read();
add(u,v),add(v,u);
se[i].u=u,se[i].v=v;
}
for(int i=;i<=n;i++){
for(int j=head[i];j!=-;j=x[j].nex){
kk[i][++cntcnt[i]]=x[j].v;
}
sort(kk[i]+,kk[i]+cntcnt[i]+);
}
delu=-,delv=-;
if(m==n-){
st[]=;
st[st[]]=;
vis[]=;
dfs(,);
for(int i=;i<=st[];i++) cout<<st[i]<<" ";
return ;
}
else{
for(int i=;i<=m;i++){
pig=;
memset(vis,,sizeof(vis));
delu=se[i].u,delv=se[i].v;
st[]=;
st[]=;
vis[]=;
dfs(,);
if(st[]!=n) continue;
bool ff=;
for(int j=;j<=n;j++){
if(st[j]>da[j]){ff=;break;}
if(st[j]<da[j]){ff=;break;}
}
if(ff)
for(int j=;j<=n;j++) da[j]=st[j]; }
for(int j=;j<=n;j++) printf("%d ",da[j]);
return ;
}
}
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
struct node{
int u,v,nex;
}x[];
int head[];
int cnt,n,m,inf=;
void add(int u,int v){
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
int st[],vis[],delu,delv,tot;
int da[];
int pig;
void dfs(int f,int fath){
if(pig==) return;
int son=;
for(int i=head[f];i!=-;i=x[i].nex){
if((delu==f&&delv==x[i].v)||(delu==x[i].v&&delv==f)) continue;
if(x[i].v==fath) continue;
if(vis[x[i].v]) continue;
if((delu==f&&delv==x[i].v)||(delu==x[i].v&&delv==f)) continue;
if(x[i].v==fath) continue;
if(vis[x[i].v]) continue;
son++;
}
while(son!=){
int minn=inf,pos=-;
for(int i=head[f];i!=-;i=x[i].nex){
if((delu==f&&delv==x[i].v)||(delu==x[i].v&&delv==f)) continue;
if(x[i].v==fath) continue;
if(vis[x[i].v]) continue;
if(x[i].v<minn){
minn=x[i].v;
pos=x[i].v;
}
}
if(pos==-) break;
vis[pos]=;
st[++st[]]=pos;
if(st[st[]]>da[st[]]&&pig!=){pig=;return;}
if(st[st[]]<da[st[]]){pig=;}
dfs(pos,f);
son--;
}
return;
}
struct node1{
int u,v;
}se[];
int main(){
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
memset(da,,sizeof(da));
memset(head,-,sizeof(head));
n=read(),m=read();
for(int i=;i<=m;i++){
int u=read(),v=read();
add(u,v),add(v,u);
se[i].u=u,se[i].v=v;
}
delu=-,delv=-;
if(m==n-){
st[]=;
st[st[]]=;
dfs(,);
for(int i=;i<=st[];i++) cout<<st[i]<<" ";
return ;
}
else{
for(int i=;i<=m;i++){
pig=;
memset(vis,,sizeof(vis));
delu=se[i].u,delv=se[i].v;
st[]=;
st[]=;
vis[]=;
dfs(,);
if(st[]!=n) continue;
bool ff=;
for(int j=;j<=n;j++){
if(st[j]>da[j]){ff=;break;}
if(st[j]<da[j]){ff=;break;}
}
if(ff){
for(int j=;j<=n;j++) da[j]=st[j];
}
}
for(int j=;j<=n;j++) cout<<da[j]<<" ";
cout<<endl;
return ;
}
}

考场代码

$update\space at\space 20190926$

突然想写一发 $O(n\log n)$ 的做法。

考虑如何对于基环树不删边求解,对于基环树可以对基环树的一个点暂时不走然后在通过另一侧的环经过。

然后记一下若能返悔最优的点即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<climits>
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
const int MAXN=;
struct node{
int u,v,nex;
}x[MAXN<<];
int head[MAXN],vis[MAXN],cnt,n,m,INF=INT_MAX;
void add(int u,int v){
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
vector<int> vec;
namespace Tree{
void dfs(int u,int fath){
priority_queue<int> que;vec.push_back(u);
for(int i=head[u];i!=-;i=x[i].nex){
if(x[i].v==fath) continue;
que.push(-x[i].v);
}while(!que.empty()){
int xx=-que.top();que.pop();
dfs(xx,u);
} return;
}
void Solve(){
dfs(,);
for(int i=;i<vec.size();i++) printf("%d ",vec[i]);printf("\n");exit();
}
}
namespace RingTree{
int cir[MAXN],vis[MAXN];
bool flag;
void dfs1(int u,int fath){
vis[u]=;
for(int i=head[u];i!=-;i=x[i].nex){
if(x[i].v==fath) continue;
if(vis[x[i].v]) {cir[x[i].v]=cir[u]=;flag=;return;}
dfs1(x[i].v,u);
if(cir[x[i].v]&&flag){if(cir[u]) flag=;cir[u]=;return;}
}return;
}
void dfs2(int u,int fath,int res){
if(vis[u]) return;
vis[u]=;vec.push_back(u);
priority_queue<int> que;
for(int i=head[u];i!=-;i=x[i].nex){
if(x[i].v==fath||vis[x[i].v]) continue;
que.push(-x[i].v);
}
while(!que.empty()){
int xx=-que.top();que.pop();
if(que.empty()&&cir[xx]&&flag&&xx>res){flag=;return;}
if(!que.empty()&&cir[u]) dfs2(xx,u,-que.top());
else dfs2(xx,u,res);
}return;
}
void Solve(){
dfs1(,);memset(vis,,sizeof(vis));flag=;dfs2(,,INF);
for(int i=;i<vec.size();i++) printf("%d ",vec[i]);printf("\n");exit();
}
}
int main(){
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
memset(head,-,sizeof(head));
n=read(),m=read();
for(int i=;i<=m;i++){int u=read(),v=read();add(u,v),add(v,u);}
if(m==n-) Tree::Solve();
if(m==n) RingTree::Solve();
}

$5.game$

$65$分找规律。

考场代码(附$dfs$)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define int long long
#define mod 1000000007
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
int n,m,a[][],k,ans,cnt_dig[][],cnt_zimu[][],dig[],zimu[];
void dfs1(int x,int y){
if(x==n&&y==m){
cnt_dig[][]++;
for(int i=;i<=k;i++) cnt_dig[cnt_dig[][]][i]=dig[i],cnt_zimu[cnt_dig[][]][i]=zimu[i];
return;
}
if(x+<=n){
zimu[++k]=;
dig[k]=a[x+][y];
dfs1(x+,y);
k--;
}
if(y+<=m){
zimu[++k]=;
dig[k]=a[x][y+];
dfs1(x,y+);
k--;
}
return;
}
bool check(){
memset(dig,,sizeof(dig));
memset(zimu,,sizeof(zimu));
memset(cnt_dig,,sizeof(cnt_dig));
memset(cnt_zimu,,sizeof(cnt_zimu));
dfs1(,);
bool ff=;
for(int i=;i<=cnt_dig[][];i++){
for(int j=;j<=cnt_dig[][];j++){
if(i==j) continue;
int st=;
for(int p=;p<=n+m-;p++){
if(cnt_zimu[i][p]<cnt_zimu[j][p]){st=;break;}
if(cnt_zimu[i][p]>cnt_zimu[j][p]){st=;break;}
}
if(st==){
int sry=;
for(int p=;p<=n+m-;p++){
if(cnt_dig[i][p]>cnt_dig[j][p]){sry=;break;}
if(cnt_dig[i][p]<cnt_dig[j][p]){sry=;break;}
}
if(sry==)return ;
}
}
}
return ;
}
int tot;
void dfs(int h,int l){
if(h==n+){
if(check()) {
ans++;
ans%=mod;
}
return;
}
if(l!=m){
a[h][l]=;
dfs(h,l+);
a[h][l]=;
dfs(h,l+);
}
else{
a[h][l]=;
dfs(h+,);
a[h][l]=;
dfs(h+,);
}
}
int query(int x,int y){
if(x==){
if(y==) return ;
if(y==) return ;
if(y==) return ;
}
if(x==){
if(y==) return ;
if(y==) return ;
if(y==) return ;
}
if(x==){
if(y==) return ;
if(y==) return ;
if(y==) return ;
}
}
signed main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
n=read(),m=read();
if(n<=&&m<=){cout<<query(n,m);return ;}
if(n==){
int ans=;
for(int i=;i<=m;i++) ans*=,ans%=mod;
cout<<ans;
return ;
}
if(n==){
int ans=;
for(int i=;i<=m-;i++) ans*=,ans%=mod;
cout<<ans;
return ;
}
if(n==){
int ans=;
for(int i=;i<=m-;i++) ans*=,ans%=mod;
cout<<ans;
return ;
}
return ;
}

$6.defense$

$44$分的暴力

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
struct node{
int u,v,nex;
}x[];
int n,m,val[],cnt,head[];
void add(int u,int v){
x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
}
int tot,dp[][],px,bx,py,by,inf;
char str[];
void dfs(int f,int fath){
int son=;
for(int i=head[f];i!=-;i=x[i].nex){
if(x[i].v==fath) continue;
son++;
}
if(son==){
if(f==px||f==py){
if(f==px){
if(bx==) dp[f][]=val[f],dp[f][]=inf;
if(bx==) dp[f][]=,dp[f][]=inf;
}
if(f==py){
if(by==) dp[f][]=val[f],dp[f][]=inf;
if(by==) dp[f][]=val[],dp[f][]=inf;
}
}
else{
dp[f][]=;
dp[f][]=val[f];
}
return;
}
for(int i=head[f];i!=-;i=x[i].nex){
if(x[i].v==fath) continue;
dfs(x[i].v,f);
if(f==px||f==py){
if(f==px){
if(bx==){
dp[f][]+=min(dp[x[i].v][],dp[x[i].v][]);
if(min(dp[x[i].v][],dp[x[i].v][])==inf) dp[f][]=inf;
}
if(bx==){
dp[f][]+=dp[x[i].v][];
if(dp[x[i].v][]==inf) dp[f][]=inf;
}
}
if(f==py){
if(by==){
dp[f][]+=dp[x[i].v][];
if(dp[x[i].v][]==inf) dp[f][]=inf;
}
if(by==){
dp[f][]+=min(dp[x[i].v][],dp[x[i].v][]);
if(min(dp[x[i].v][],dp[x[i].v][])==inf) dp[f][]=inf;
}
}
}
else{
dp[f][]+=dp[x[i].v][];
dp[f][]+=min(dp[x[i].v][],dp[x[i].v][]);
if(min(dp[x[i].v][],dp[x[i].v][])==inf) dp[f][]=inf;
if(dp[x[i].v][]==inf) dp[f][]=inf;
}
}
if(dp[f][]!=inf) dp[f][]+=val[f];
return;
}
signed main(){
// freopen("defense.in","r",stdin);
// freopen("defense.out","w",stdout);
inf=<<-;
memset(head,-,sizeof(head));
n=read(),m=read();
scanf("%s",str+); for(int i=;i<=n;i++) val[i]=read();
for(int i=;i<n;i++){
int u=read(),v=read();
add(u,v),add(v,u);
}
while(m--){
px=read(),bx=read(),py=read(),by=read();
memset(dp,,sizeof(dp));
dp[px][bx^]=inf,dp[py][by^]=inf;
dfs(,);
int k=min(dp[][],dp[][]);
if(k>=inf){cout<<-<<endl;continue;}
printf("%lld\n",k);
}
}

然后直接动态$dp$即可。

update:分数线出来了,提高$300$,普及$190$。

NOIP2018普及&提高题解的更多相关文章

  1. 『NOIP2018普及组题解』

    标题统计 题目描述 凯凯刚写了一篇美妙的作文,请问这篇作文的标题中有多少个字符? 注意:标题中可能包含大.小写英文字母.数字字符.空格和换行符.统计标题字 符数时,空格和换行符不计算在内. 输入格式 ...

  2. 【NOIP2018】提高组题解

    [NOIP2018]提高组题解 其实就是把写过的打个包而已 道路铺设 货币系统 赛道修建 旅行 咕咕咕 咕咕咕

  3. 【资源】NOIP2013测试数据senior&sol;junior 普及&sol;提高 数据

    https://yunpan.cn/cRSepfcG4XX3V  访问密码 48e1 NOIP2013测试数据senior/junior 普及/提高 数据都在了

  4. NOIP2008普及组题解

    NOIP2008普及组题解 从我在其他站的博客直接搬过来的 posted @ 2016-04-16 01:11 然后我又搬回博客园了233333 posted @ 2016-06-05 19:19 T ...

  5. NOIP2018普及初赛解析

    2018年第二十四届全国青少年信息学奥林匹克联赛初赛普及组真题解析 一.单项选择题 1. 以下哪一种设备属于输出设备:(D) A.扫描仪 _B.键盘C. 鼠标 _D. 打印机 解析:送分题,前三个都是 ...

  6. NOIP初赛知识点大全-普及&plus;提高组

    NOIP初赛知识点大全-普及+提高组 https://mp.weixin.qq.com/s/vSXLDxmbBoFfZPzD8lrt3w

  7. NOIP2018普及组复赛游记

    2018年11月10日,NOIP2018普及组复赛. 这是我初中阶段最后一次复赛了. 和往常一样,我们在预定的早上7点,没有出发. 10分钟之后,人终于到齐了,于是出发了,一路无话. 到了南航,合照三 ...

  8. NOIP2018普及组初赛解题报告

    本蒟蒻参加了今年的NOIP2018普及组的初赛 感觉要凉 总而言之,今年的题要说完全没有难度倒也不至于,还有不少拼RP的题,比如第一次问题求解考逻辑推理,第一次完善程序考双链表等 下面我就和大家一起看 ...

  9. &lbrack;NOIP2018&rsqb;普及组初赛题解

    老师布置的作业,借博客这个平台一用 [总体感觉]对我而言比去年的难度大……特别是最后一题. 选择题 1.D 打印机属于输出设备 2.D 将全部进制转换为10进制进行对比,我的方法是每一位乘以进制的位数 ...

随机推荐

  1. Window10可用的转串口驱动CH340

    下载地址:http://pan.baidu.com/s/1cvCNtO

  2. objective c&comma; category 和 protocol 中添加property

    property的本质是实例变量 + getter 和 setter 方法 category和protocol可以添加方法 category 和 protocol中可以添加@property 关键字 ...

  3. Spring实战5:基于Spring构建Web应用

    主要内容 将web请求映射到Spring控制器 绑定form参数 验证表单提交的参数 对于很多Java程序员来说,他们的主要工作就是开发Web应用,如果你也在做这样的工作,那么你一定会了解到构建这类系 ...

  4. Learn CSS

    韩顺平老师的CSS讲的还是很简单的,仅作入门. div+css的介绍    div+css是什么. div元素是用来为HTML文档内大块(block-level)的内容提供结构和背景的元素. css是 ...

  5. 迭代 Iterate

    迭代:指按照某种顺序逐个访问列表中的每一项.比如:for语句 逐个访问: lst = ['q', 'i', 'w', 's', 'i', 'r'] for i in lst: print (i), # ...

  6. URLs对象 blob URL

    把指向数据的URL保存到file或者blob对象里,好处就是不需要先文件读取内容然后才能用.   function createObjectURL(blob){if (window.URL){retu ...

  7. Linux 学习之路 --------ip地址虚拟网络

    // ifconfig 查看IP地址 网络信息   我的IP  39.161.136.25 ①     为网卡临时配置IP地址 ifconfig eth0 39.161.136.5 (netmask ...

  8. mysql 设置 innodb&lowbar;print&lowbar;all&lowbar;deadlocks&equals;ON&comma; 保存死锁日志

    Introduced 5.6.2 Command-Line Format --innodb-print-all-deadlocks=# System Variable Name innodb_prin ...

  9. 一小时入门webpack

    webpack现在已经成为了大众化的项目必要脚手架,基本上现在的很多项目都需要webpack,由于webpack的出现glup和grunt已经完败,今天我们来说一下webpack如何使用. 首先我们需 ...

  10. 最新版的Chrome 69&period;0 设置始终开启flash而不是先询问

    ## 69.0 之前的版本 ##   1.打开 chrome://settings/content/flash   2.禁止网站运行Flash -> 改为“Ask (Default)”   3. ...