第一次考$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/junior 普及/提高 数据

    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初赛知识点大全-普及+提高组

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

  7. NOIP2018普及组复赛游记

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

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

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

  9. P5017 [NOIP2018 普及组] 摆渡车

    P5017 [NOIP2018 普及组] 摆渡车 题目 P5017 思路 将实际问题抽象后,不难发现这是一个 区间 \(DP\) 我们不妨认为时间是一条数轴,每名同学按照到达时刻分别对应数轴上可能重合 ...

随机推荐

  1. Selenium(Python)调用pywin32上传图片

    import unittestfrom time import sleep import osfrom selenium import webdriverimport win32apiimport w ...

  2. Siki_Unity_2-1_API常用方法和类详细讲解(下)

    Unity 2-1 API常用方法和类详细讲解(下) 任务101&102:射线检测 射线origin + direction:射线检测:射线是否碰撞到物体 (物体需要有碰撞器),碰撞物体的信息 ...

  3. DP动态规划练习

    先来看一下经典的背包问题吧 http://www.cnblogs.com/Kalix/p/7617856.html  01背包问题 https://www.cnblogs.com/Kalix/p/76 ...

  4. @meida 媒体查询

    示例 @meida 媒体查询 在进行书写的时候需要考虑到加载顺序和样式权重使用meida响应式实现不同宽度布局示例 常用工具 https://mydevice.io 参考链接 https://deve ...

  5. logisitic回归

    线性回归目的是找到一条直线(或者超平面)尽可能地接近所有的训练数据点,而对数几率回归的目的是找到一条直线(或者超平面)尽可能地分开两种不同类别的数据点. 对数几率回归感觉更像是一个分类问题.https ...

  6. 特殊符号 & 以太坊

    &表示取二进制的末尾 &1表示如果末尾是奇数和偶数两种情况 0 偶数 1奇数 举例子: int a=1;int p=&a; 其中,p是指针,&a就是将a在内存中的实际地 ...

  7. array.some() 方法兼容ie8

    在第 5 版时,some 被添加进 ECMA-262 标准:这样导致某些实现环境可能不支持它.你可以把下面的代码插入到脚本的开头来解决此问题,从而允许在那些没有原生支持它的实现环境中使用它.该算法是  ...

  8. HDU 1512 Monkey King(左偏树)

    Description Once in a forest, there lived N aggressive monkeys. At the beginning, they each does thi ...

  9. C语言实训——扑克牌洗牌程序

    说明此程序本来是21点扑克程序的一个被调函数,在这里我单独将它拿出来作为一个小程序. #include<stdio.h> #include<time.h> #include&l ...

  10. Thunder团队第三周 - Scrum会议3

    Scrum会议3 小组名称:Thunder 项目名称:i阅app Scrum Master:代秋彤 工作照片: 参会成员: 王航:http://www.cnblogs.com/wangh013/ 李传 ...