【NOIP2018模拟赛】

A. 【NOIP2018模拟赛】刺客信条(AC)

这道题第一眼看上去可能会想到找路径然后算距离,但发现这是不现实的。

所以我们通过限定答案的值来判断是否满足。

将答案设为 r (半径) ,每个棋盘上的点都由半径做圆,然后判断路径不触碰到圆的最大半径。

我们利用并查集将每个圆与墙进行处理,然后通过二分答案进行判断。

p.s. 记得要加eps (一个极小的数,调整精度)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef double db;
 4 
 5 const db e=1e-4;
 6 const int N=2011;
 7 int n,m,k,fa[N];
 8 db x[N],y[N],dis[N][N];
 9 
10 int getf(int x){
11     if(fa[x]==x) return x;
12     else return fa[x]=getf(fa[x]);
13 }
14 
15 void exchange(int x,int y){
16     fa[getf(x)]=getf(y);
17 }
18 
19 db two(db a){
20     return a*a;
21 }
22 
23 db d(int i,int j){
24     return sqrt(two(x[i]-x[j])+two(y[i]-y[j]));
25 }
26 
27 bool pd(double r){
28     for(int i=1;i<=k+4;i++) fa[i]=i;
29     for(int i=1;i<=k;i++){
30         if(r-x[i]>e) exchange(k+1,i);//左墙 
31         if(r-y[i]>e) exchange(k+2,i);//底墙 
32         if(r-(n-x[i])>e) exchange(k+3,i);//右墙 
33         if(r-(m-y[i])>e) exchange(k+4,i);//顶墙 
34         for(int j=i+1;j<=k;j++){
35             if(r*2-dis[i][j]>e || (fabs(r*2-dis[i][j])<e)) exchange(i,j);
36         } 
37     }
38     if(getf(k+1)==getf(k+2)) return true;
39     if(getf(k+1)==getf(k+3)) return true;
40     if(getf(k+2)==getf(k+4)) return true;
41     if(getf(k+3)==getf(k+4)) return true;
42     return false;
43 }
44 
45 int read(){
46     int x=0,f=1;
47     char s=getchar();
48     while(!isdigit(s)) f*=(s=='-')? -1:1,s=getchar();
49     do x=(x<<1)+(x<<3)+(s^48),s=getchar();
50     while(isdigit(s));
51     return x*f;
52 }
53 
54 int main(){
55     n=read(),m=read(),k=read();
56     for(int i=1;i<=k;i++){
57         scanf("%lf%lf",&x[i],&y[i]);
58     }
59     for(int i=1;i<=k;i++){
60         for(int j=i+1;j<=k;j++){
61             dis[i][j]=d(i,j);
62         }
63     }
64     db l=0,r=1000000;
65     while(r-l>e){
66         db mid=(l+r)/2;
67         if(pd(mid)) r=mid;
68         else l=mid;
69     }
70     printf("%.2f",l);
71     return 0;
72 } 

C. 【NOIP2018模拟赛】传送门 (portal)

一道树形dp的题。

设f[][]表示状态

f[x][0]:x和x的子树里没有传送门
f[x][1]:x和x的子树里有传送门

状态转移方程:
f[x][0]+=f[y][0]+2*w[i];

f[x][1]+=min(f[y][0]+w[i]-d[y],f[y][1]+w[i]*2);

code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN=1e6+5;
 4 const long long null=1e15;
 5 
 6 int n;
 7 int head[MAXN],to[MAXN*2],next[MAXN*2],w[MAXN*2],cnt;
 8 long long f[MAXN][2],d[MAXN];
 9 
10 void add(int u,int v,int l){
11     cnt++;
12     next[cnt]=head[u];
13     to[cnt]=v;
14     w[cnt]=l;
15     head[u]=cnt;
16 }
17 
18 void dp(int x,int fa){
19     for(int i=head[x];i;i=next[i]){
20         int y=to[i];
21         if(y==fa)
22             continue;
23         dp(y,x);
24         d[x]=max(d[x],d[y]+w[i]);
25         f[x][0]+=f[y][0]+2*w[i];
26         f[x][1]+=min(f[y][0]+w[i]-d[y],f[y][1]+w[i]*2);
27     }
28 }
29 
30 int main(){
31     cin>>n;
32     for(int i=1;i<n;i++){
33         int u,v,a;
34         scanf("%d%d%d",&u,&v,&a);
35         add(u,v,a);
36         add(v,u,a);
37     }
38     dp(1,1);
39     cout<<min(f[1][1],f[1][0]);
40     return 0;
41 }

B. 【NOIP2018模拟赛】黑暗之魂(darksoul)

这是一颗环套树

题目要求的是这棵环套树的直径,再+1就是答案了。

我们把该环提出来,在上面操作。

那么直径要么是环上某点的子树内直径,要么是环上某两点子树内最长链再加一段环上路径。

子树内直径和最长链我们先算出来,剩下的就是如何求出环上两点使之匹配出来最大值。

枚举环上一点 i ,同时维护一个指针 j  往后指,表示从 i+1  到 j  是近一些,而 j 之后的点呢会绕环一圈来走回 i  更近一些。

那么 i+1  到 j的我们用一个单调队列来求最大值,绕一周的用一个后缀最大值算就好了。

  1 #include<cstdio>
  2 #include<cctype>
  3 using namespace std;
  4 typedef long long ll;
  5 const int N=1e6+5;
  6 int tot=1,top,qx,qy,node;
  7 ll ans,mx;
  8 bool pd;
  9 int first[N],nex[N<<1],en[N<<1],w[N<<1];
 10 int st[N],dfn[N],d[N],len[N],col[N],q[N];
 11 ll suf[N],pre[N],f[N];
 12 bool bz[N];
 13 inline int read(){
 14     int x=0,f=1;
 15     char s=getchar();
 16     while(!isdigit(s)) f*=(s=='-')? -1:1,s=getchar();
 17     do x=(x<<1)+(x<<3)+(s^48),s=getchar();
 18     while(isdigit(s));
 19     return x*f;
 20 }
 21 inline ll max(ll x,ll y)
 22 {
 23     return x>y?x:y;
 24 }
 25 inline void in(int x,int y,int z)
 26 {
 27     nex[++tot]=first[x];
 28     first[x]=tot;
 29     en[tot]=y;
 30     w[tot]=z;
 31 }
 32 void dfs(int x,int y)
 33 {
 34     st[++top]=x;
 35     dfn[x]=top;
 36     for(int i=first[x];i && !pd;i=nex[i])
 37         if(i^y)
 38         {
 39             if(dfn[en[i]])
 40             {
 41                 for(int j=dfn[en[i]];j<=top;j++)
 42                 {
 43                     d[++d[0]]=st[j];
 44                     bz[st[j]]=true;
 45                 }
 46                 pd=true;
 47                 return;
 48             }
 49             dfs(en[i],i^1);
 50         }
 51     top--;
 52 }
 53 void find(int x,int y,ll z,ll &num)
 54 {
 55     if(z>num) num=z;
 56     for(int i=first[x];i;i=nex[i])
 57         if(en[i]^y && en[i]^x) find(en[i],x,z+w[i],num);
 58 }
 59 void get(int x,int y)
 60 {
 61     if(y==d[0]) return;
 62     for(int i=first[x];i;i=nex[i])
 63         if(en[i]==d[y+1])
 64         {
 65             len[y]=w[i];
 66             get(en[i],y+1);
 67         }
 68 }
 69 void dg(int x,int y,ll z)
 70 {
 71     if(z>mx) mx=z,node=x;
 72     col[x]=tot;
 73     for(int i=first[x];i;i=nex[i])
 74         if(en[i]^y && en[i]^x && !bz[en[i]]) dg(en[i],x,z+w[i]);
 75 }
 76 void dg1(int x,int y,ll z)
 77 {
 78     if(z>mx) mx=z,node=x;
 79     for(int i=first[x];i;i=nex[i])
 80         if(en[i]^y && en[i]^x && col[en[i]]==tot) dg1(en[i],x,z+w[i]);
 81 }
 82 int main()
 83 {
 84     int n=read();
 85     for(int i=1;i<=n;i++)
 86     {
 87         int x=read(),y=read(),z=read();
 88         in(x,y,z);
 89         in(y,x,z);
 90     }
 91     dfs(1,0);
 92     tot=0;
 93     for(int i=1;i<=d[0];i++)
 94     {
 95         for(int j=first[d[i]];j;j=nex[j])
 96             if(!bz[en[j]]) find(en[j],d[i],w[j],f[i]);
 97         node=mx=0;
 98         tot++;
 99         dg(d[i],0,0);
100         dg1(node,0,0);
101         ans=max(ans,mx);
102         if(f[i]>ans) ans=f[i];
103     }
104     get(d[1],1);
105     for(int i=first[d[d[0]]];i;i=nex[i])
106         if(en[i]==d[1])
107         {
108             len[d[0]]=w[i];
109             break;
110         }
111     for(int i=2;i<=d[0];i++) pre[i]=pre[i-1]+len[i-1];
112     for(int i=2;i<=d[0];i++) suf[i]=pre[d[0]]+len[d[0]]-pre[i]+f[i];
113     for(int i=d[0]-1;i>1;i--) suf[i]=max(suf[i+1],suf[i]);
114     int l=1,r=0;
115     for(int i=1,j=1;i<d[0];i++)
116     {
117         while(l<r && q[l]<=i) l++;
118         while(j<d[0] && pre[j+1]-pre[i]<=pre[d[0]]-pre[j+1]+len[d[0]]+pre[i])
119         {
120             j++;
121             while(l<=r && f[q[r]]+pre[q[r]]<=f[j]+pre[j]) r--; 
122             q[++r]=j;
123         }
124         ll num=0;
125         if(j<d[0]) num=suf[j+1]+pre[i];
126         if(i<j) num=max(num,f[q[l]]+pre[q[l]]-pre[i]);
127         ans=max(ans,num+f[i]);
128     }
129     printf("%lld",ans+1);
130     return 0;
131 }
原文地址:https://www.cnblogs.com/lirh04/p/12392524.html