zoukankan      html  css  js  c++  java
  • [BZOJ1911][BZOJ1912][BZOJ1913]APIO2010解题报告

    特别行动队

    Description

     
      这个好像斜率优化不是一般地明显了啊...只不过要分a的正负两种情况考虑是维护上凸还是下凸
     1 /**************************************************************
     2     Problem: 1911
     3     User: mjy0724
     4     Language: C++
     5     Result: Accepted
     6     Time:1688 ms
     7     Memory:24248 kb
     8 ****************************************************************/
     9  
    10 #include<cstdio>
    11 #include<cstdlib>
    12 #include<cstring>
    13 const int maxn=1000010;long long INF=10000000000000007;
    14 long long n,a,b,c,sum[maxn],opt[maxn],f[maxn];
    15 long long g(int j,int k){
    16     if (2*a*(sum[j]-sum[k])==0)
    17     {
    18         if (f[j]+a*sum[j]*sum[j]-b*sum[j]-(f[k]+a*sum[k]*sum[k]-b*sum[k])>0) return INF;
    19         else return -INF;
    20     }
    21     return (f[j]+a*sum[j]*sum[j]-b*sum[j]-(f[k]+a*sum[k]*sum[k]-b*sum[k]))/(2*a*(sum[j]-sum[k]));
    22 }
    23  
    24 int main(){ 
    25     scanf("%lld",&n);
    26     scanf("%lld%lld%lld",&a,&b,&c);
    27     for (int i=2;i<=n+1;i++) scanf("%lld",&sum[i]),sum[i]+=sum[i-1];
    28     int head=1,tail=1;opt[1]=1;f[1]=0;
    29     for (int i=2;i<=n+1;i++){
    30         if (a>=0) while (head<tail&&g(opt[head],opt[head+1])>sum[i]) head++;       
    31         else while (head<tail&&g(opt[head],opt[head+1])<sum[i]) head++;   
    32         int j=opt[head];
    33         f[i]=f[j]+a*(sum[i]-sum[j])*(sum[i]-sum[j])+b*(sum[i]-sum[j])+c;    
    34         if (a>=0) while (head<tail&&g(opt[tail-1],opt[tail])<g(opt[tail],i)) tail--;
    35         else while (head<tail&&g(opt[tail-1],opt[tail])>g(opt[tail],i)) tail--;
    36         opt[++tail]=i;
    37     }
    38     printf("%lld
    ",f[n+1]);
    39     return 0;
    40 }

    patrol 巡逻

    Description

     
      首先对于k=1的情况,稍微观察就可以看出来,假设连上这条边之后原图形成了一个由n个点组成的环
      原先经过这些点的边数为2(n-1),如今为n,所以减少的路径为(n-2)
      
      如果是再连一条边的话,如果不与第一条形成的环相交(指有边重合),那么显然规律不变
      如果有边重叠了,设重叠的边数为x,那么原先经过这些点的边数为2(n--1-x),如今为n,所以减少的路径为n-2-2x
      也就是相对于第一种规律,每重叠一条边,减少的路径数-2
      
      那么我们不妨令每条边初始边权为1,第一问可以通过求树的直径得到
      对于第一问经过的路径,边权改为-1,也就实现了每重叠一条边,减少的路径数-2的效果
     
     1 /**************************************************************
     2     Problem: 1912
     3     User: mjy0724
     4     Language: C++
     5     Result: Accepted
     6     Time:708 ms
     7     Memory:5288 kb
     8 ****************************************************************/
     9  
    10 #include<cstdio>
    11 #include<cstdlib>
    12 #include<cstring>
    13 const int maxn=100010,maxm=200010;
    14 int n,k,e,link[maxn],next[maxm],fa[maxm],pos1[maxn],pos2[maxn],w[maxm],ans,sum,s;
    15 void add(int x,int y){
    16     fa[++e]=y;next[e]=link[x];link[x]=e;w[e]=1;
    17     fa[++e]=x;next[e]=link[y];link[y]=e;w[e]=1;
    18 }
    19  
    20 int dfs(int p,int fat){
    21     int max1=0,max2=0;
    22     for (int i=link[p];i;i=next[i]) if (fa[i]!=fat){
    23         int tmp=dfs(fa[i],p)+w[i];
    24         if (tmp>max1){
    25             max2=max1;max1=tmp;pos2[p]=pos1[p];pos1[p]=i;
    26         }else if (tmp>max2) max2=tmp,pos2[p]=i;
    27     }
    28     if (max1+max2>ans) {
    29         ans=max1+max2;s=p;
    30     }
    31     return max1;
    32 }
    33  
    34 int main(){
    35     scanf("%d%d",&n,&k);
    36     int e=0,x,y;
    37     for (int i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y);
    38     dfs(1,0);sum=ans;
    39     if (k==1){printf("%d
    ",2*(n-1)-(ans-1));return 0;}
    40     for (int i=pos1[s];i;i=pos1[fa[i]]) w[i]=-1;
    41     for (int i=pos2[s];i;i=pos1[fa[i]]) w[i]=-1;
    42     ans=0;dfs(1,0);
    43     printf("%d
    ",2*(n-1)-(ans-1)-(sum-1));
    44     return 0;
    45 }

    signaling 信号覆盖


    Description

      我们考虑四边形
      如果是凸的四边形,当对角和>180度的时候能够信号覆盖4个,也就是一个凸四边形能带来2种答案为4的取法
      凹多边形只要取外面的3个点可以带来1种答案为4的取法 剩下的情况答案都为3
      凹多边形的取法与凸多边形的取法是已知一个可以计算出另一个的
      于是我们可以先考虑计算凹多边形的取法
      先枚举位于中间的点,容易看出,剩下三个点构成的三角形能够包含中间点
      相反的,不能包含的就是不能构成凹多边形的,于是我们可以计算这些不包含的方案数
      对所有的点按照中间点进行极角排序,然后单调队列维护每个点能够到达的最远点,使得两点间的所有点的极角差都在180度之间
      可以用叉积简化运算
      最后注意一些乘法加法运算的细节就可以了
     1 /**************************************************************
     2     Problem: 1913
     3     User: mjy0724
     4     Language: C++
     5     Result: Accepted
     6     Time:1996 ms
     7     Memory:1356 kb
     8 ****************************************************************/
     9  
    10 #include<cstdio>
    11 #include<cstdlib>
    12 #include<cstring>
    13 #include<cmath>
    14 #include<algorithm>
    15 #include<iostream>
    16 #define ll long long
    17 #define maxn 1510
    18 struct point{
    19     ll x,y;
    20     double angle;   
    21 };
    22 ll n,an,b;
    23 point p[maxn],a[maxn];
    24 ll cross(point p0,point p1,point p2){
    25     return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
    26 }
    27 void sortf(int l,int r){
    28     int i=l,j=r;double mid=p[(l+r) >> 1].angle;
    29     do{
    30         while (i<r&&p[i].angle<mid) i++;
    31         while (l<j&&p[j].angle>mid) j--;
    32         if (i<=j){
    33             point tmp=p[i];p[i]=p[j];p[j]=tmp;
    34             i++;j--;
    35         }
    36     }while (i<=j);
    37     if (i<r) sortf(i,r);
    38     if (l<j) sortf(l,j);
    39 }
    40 ll calc(int x){
    41     int tot=0;
    42     for (int i=1;i<=n;i++) {if (i!=x) p[++tot]=a[i];else p[0]=a[i];}
    43     for (int i=1;i<=tot;i++) p[i].angle=atan2(p[i].y-p[0].y,p[i].x-p[0].x);
    44     sortf(1,tot);
    45     ll ans=(n-1)*(n-2)*(n-3)/6; 
    46     ll tail=2,t=0;
    47     for (int i=1;i<=tot;i++){    
    48         while (cross(p[0],p[i],p[tail])>=0) {tail=tail%tot+1;t++;if (tail==i) break;}        
    49         ans-=t*(t-1)/2;t--; 
    50     }   
    51     return ans;
    52 }
    53  
    54 int main(){
    55     scanf("%lld",&n);   
    56     for (int i=1;i<=n;i++) scanf("%lld%lld",&a[i].x,&a[i].y);    
    57     ll an=0;for (int i=1;i<=n;i++) an+=calc(i);  
    58     ll b=n*(n-3)*(n-2)*(n-1)/24-an,c=2*b+an,d=(n-2)*n*(n-1)/6;
    59     printf("%lf",(double)(c*4+(d-c)*3)/d);
    60     return 0;
    61 }
  • 相关阅读:
    Maven2-profile多环境配置
    Maven-setting.xml详解
    Maven-通过命令操作maven项目
    Maven-eclipse运行maven命令
    Eclipse-导入maven项目
    Maven-搭建maven web项目
    Maven-搭建普通maven项目
    Maven-pom.xml详解
    Maven-生命周期
    Maven-常用命令
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4489591.html
Copyright © 2011-2022 走看看