zoukankan      html  css  js  c++  java
  • HZOJ 单

    两个子任务真的是坑……考试的时候想到了60分的算法,然而只拿到了20分(各种沙雕错,没救了……)。

    算法1:

    对于测试点1,直接n遍dfs即可求出答案,复杂度O(n^2),然而还是有好多同学跑LCA/最短路……

    期望得分10;

    算法2(搬运题解,因为这个我没有想到……):

    t=1的数据最直接的想法是枚举所有可能的a[]数组判断是否可行.第2个测试点n<=5,1<=a[i]<=20.注意20^5=3200000,直接暴力搜索a[i]的取值是可以承受的,可以通过第2个测试点,期望得分10分,结合算法1,期望得分20分.

    算法3:

    对于测试点6,7。我们可以发现每个点的dis都有联系,这不就是二次扫描与换根吗(具体看代码理解)。结合算法2期望得分40;

     1 void dfs2(int x,int fa)
     2 {
     3     for(int i=f(x);i;i=n(i))
     4     if(v(i)!=fa)
     5     {    
     6         b[v(i)]=b[x];
     7         b[v(i)]-=sum[v(i)];
     8         b[v(i)]+=sum[x]-sum[v(i)];
     9         sum[x]-=sum[v(i)];
    10         sum[v(i)]+=sum[x];
    11         dfs2(v(i),x);
    12         sum[v(i)]-=sum[x];
    13         sum[x]+=sum[v(i)];
    14     }
    15 }
    第二次扫描的代码

    算法4:

    t=1的数据中,b数组的表达式写出来之后,每个b[i]对应一个关于a[i]和树上两点距离的方程,例如b[1]=dis(1,1)*a[1]+dis(1,2)*a[2]+dis(1,3)*a[3]+...+dis(1,n)*a[n],于是可以列出n个方程用高斯消元求解,可以通过第2,3,4个测试点,期望得分30分,结合算法3,期望得分60分。要注意的一点是,高斯消元中要注意这句话‘if(fabs(sa[j][i])>fabs(sa[i][i]))’,本人死于此……还有不少人死于强制类型转化的四舍五入,其实printf("%0.0lf")即可;

    之后的算法题解写的已经很清晰了,我觉得我也写不了这么清楚,就直接搬运了。

    算法5:

    对于测试点5,树退化为1条链。这个测试点的作用主要在于启发选手想到正解的思路(然而我并没有什么启发……)。

    t=0时,我们分别考虑编号小于i和大于i的点对b[i]的贡献.那么离得越远的点对答案的贡献越大.分别考虑每条边对答案的贡献,那么左侧的某条边对答案的贡献就是这条边左侧全部a[i]之和.实际上,我们对a[i]分别求取两次前缀和,两次后缀和即可完成对b[i]的计算.

    记suf(i)为a[i]+a[i+1]+....+a[n-1]+a[n],pre(i)为a[1]+a[2]+...+a[i-1]+a[i],则b[i]=pre(1)+pre(2)+...+pre(i-1)+suf(i+1)+suf(i+2)+...+suf(n-1)+suf(n)

    考虑t=1的情况.

    我们知道suf(2)+suf(3)+...+suf(n)的值(即b[1]),知道pre(1) + suf(3) + suf(4) +...+suf(n)的值(即b[2]),知道pre(1)+pre(2)+suf(4)+...+suf(n)的值(即b[3]),注意到这些式子有很多项是一样的,考虑作差.可以得到下面的式子:

    b[2]-b[1]=pre(1)-suf(2),b[3]-b[2]=pre(2)-suf(3).....b[i+1]-b[i]=pre(i)-suf(i+1)                   

    这些式子是有实际意义的,考虑从b[1]变到b[2]时答案的变化量,变化的就是1和2之间连边的贡献.

    同时,记SUM=a[1]+a[2]+...+a[n-1]+a[n],显然pre(i)+suf(i+1)=SUM,因此pre(i)=SUM-suf(i+1),将上面式子中所有pre换成suf,我们就知道了

    SUM-2*suf(2) ,SUM-2*suf(3)...SUM-2*suf(n)的取值。

    注意我们将n个式子作差之后得到了n-1个等式,实际上是丢弃了一些信息,只保留了b[i]之间的相对大小而忽略了b[i]自身的数值大小.于是考虑b[1]=suf(2)+suf(3)+suf(4)+... +suf(n),我们发现suf(2)到suf(n)都恰好出现了一次,而之前得到了n-1个形如SUM-2*suf(i)的式子,将这n-1个式子相加,suf(2),suf(3)...suf(n)前面的系数都是2,SUM的系数为(n-1),那么把这个式子加上2*b[1],就得到了(n-1)*SUM,将求得的SUM代入之前的n-1个式子可以得到suf(2),suf(3),suf(4)......suf(n),差分一下即可得到a数组.

    时间复杂度O(n),可以通过第5个测试点.推出这个做法,树上的做法也就不难想了.

    算法6(满分算法):

    考虑树上的问题.

    t=0的时候,我们可以先暴力计算出b[1],然后从b[1]出发开始dfs,由某个点的父亲的b[i]推出这个点的b[i],变化的是这个点和父亲的连边的贡献,也就是这条边两侧的点的a[i]之和的差值.

    t=1的时候,顺着链上的思路,我们先随便找一个点为根建树,将有边直接相连的两个点的b[i]作差.设x的父亲为prt[x],以x为根的子树中所有a[i]之和为sum(x), SUM=a[1]+a[2]+...+a[n-1]+a[n],那么b[x]-b[prt[x]]=(SUM-sum(x))-sum(x).

    同链的情况一样,得到n-1个式子,将树根的b[i]也列出式子,可以求出全部a[i]之和,然后就可以根据之前的式子推出所有的a[i],和链的做法类似,不再赘述.

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<cmath>
      5 #define MAXN 100010
      6 #define int LL
      7 #define LL long long
      8 #define esp 1e-8
      9 #define ma(x) memset(x,0,sizeof(x))
     10 using namespace std;
     11 struct edge
     12 {
     13     int u,v,nxt;
     14     #define u(x) ed[x].u
     15     #define v(x) ed[x].v
     16     #define n(x) ed[x].nxt
     17 }ed[MAXN*2];
     18 int first[MAXN],num_e;
     19 #define f(x) first[x]
     20 int T,n,t;
     21 LL a[MAXN],b[MAXN];
     22 LL dis[MAXN],sum[MAXN];
     23 LL SUM,suf[MAXN];
     24 LL SUM_2suf[MAXN];
     25 LL SUM_2sum[MAXN];
     26 LL TSUM=0;
     27 
     28 int map[110][110];
     29 double sa[110][110],sb[110];
     30 void GS()
     31 {    
     32     for(int i=1;i<=n;i++)
     33     {
     34         for(int j=i;j<=n;j++)
     35         if(fabs(sa[j][i])>fabs(sa[i][i]))    
     36         {
     37             for(int k=1;k<=n;k++)
     38                 swap(sa[i][k],sa[j][k]);
     39             swap(sb[i],sb[j]);
     40         }
     41         for(int j=1;j<=n;j++)
     42         {
     43             if(j==i)continue;
     44             if(fabs(sa[i][i])<=esp)continue;
     45             double cal=sa[j][i]/sa[i][i];
     46             for(int k=1;k<=n;k++)
     47                 sa[j][k]-=sa[i][k]*cal;
     48             sb[j]-=sb[i]*cal;
     49         }
     50     }
     51 }
     52 void dfs(int x,int fa)
     53 {
     54     sum[x]=a[x];
     55     for(int i=f(x);i;i=n(i))    
     56     if(v(i)!=fa)
     57     {
     58         dis[v(i)]=dis[x]+1;
     59         dfs(v(i),x);
     60         sum[x]+=sum[v(i)];
     61     }
     62 }
     63 void dfs2(int x,int fa)
     64 {
     65     for(int i=f(x);i;i=n(i))
     66     if(v(i)!=fa)
     67     {    
     68         b[v(i)]=b[x];
     69         b[v(i)]-=sum[v(i)];
     70         b[v(i)]+=sum[x]-sum[v(i)];
     71         sum[x]-=sum[v(i)];
     72         sum[v(i)]+=sum[x];
     73         dfs2(v(i),x);
     74         sum[v(i)]-=sum[x];
     75         sum[x]+=sum[v(i)];
     76     }
     77 }
     78 void dfs3(int x,int fa)
     79 {    
     80     if(x!=1)SUM_2sum[x]=b[x]-b[fa];
     81     for(int i=f(x);i;i=n(i))
     82     if(v(i)!=fa)
     83         dfs3(v(i),x);
     84 }
     85 void dfs4(int x,int fa)
     86 {
     87     if(x==1)sum[x]=SUM;
     88     else    sum[x]=(SUM-SUM_2sum[x])/2;
     89     a[x]=sum[x];
     90     for(int i=f(x);i;i=n(i))
     91     if(v(i)!=fa)
     92     {
     93         dfs4(v(i),x);
     94         a[x]-=sum[v(i)];
     95     }        
     96 }
     97 inline int read();
     98 inline void add(int u,int v);
     99 signed main()
    100 {    
    101 //    freopen("in.txt","r",stdin);
    102 
    103     T=read();
    104     while(T--)    
    105     {
    106         ma(sum);ma(first);num_e=0;ma(dis);ma(a);ma(b);
    107         ma(map);ma(sa);ma(sb);ma(suf);SUM=0;ma(SUM_2suf);
    108         ma(SUM_2sum);TSUM=0;
    109         bool pd=1;
    110         n=read();int u,v;
    111         for(int i=1;i<n;i++)    
    112         {
    113             u=read(),v=read();
    114             if(v!=u+1)pd=0;
    115             add(u,v),add(v,u);
    116         }
    117         t=read();        
    118         if(t==0)
    119         {
    120             for(int i=1;i<=n;i++)a[i]=read();    
    121             if(n<=1000)
    122             {    
    123                 for(int i=1;i<=n;i++)
    124                 {
    125                     dis[i]=0;
    126                     dfs(i,0);
    127                     for(int j=1;j<=n;j++)b[i]+=a[j]*dis[j];
    128                 }
    129                 for(int i=1;i<=n;i++)
    130                     printf("%lld ",b[i]);
    131                 puts("");
    132                 continue;
    133             }
    134             else
    135             {
    136                 dis[1]=0;dfs(1,0);
    137                 for(int i=1;i<=n;i++)b[1]+=dis[i]*a[i];
    138                 dfs2(1,0);
    139                 for(int i=1;i<=n;i++)
    140                     printf("%lld ",b[i]);
    141                 puts("");
    142                 continue;
    143             }
    144         }
    145         if(t==1)
    146         {
    147             for(int i=1;i<=n;i++)b[i]=read();    
    148             if(n<=100)    
    149             {
    150                 for(int i=1;i<=n;i++)
    151                 {
    152                     dis[i]=0;dfs(i,0);
    153                     for(int j=1;j<=n;j++)map[i][j]=dis[j];
    154                 }
    155                 for(int i=1;i<=n;i++)sb[i]=b[i];
    156                 for(int i=1;i<=n;i++)
    157                     for(int j=1;j<=n;j++)sa[i][j]=map[j][i];
    158                 GS();
    159                 for(int i=1;i<=n;i++)
    160                     printf("%0.0lf ",sb[i]/sa[i][i]);
    161                 puts("");
    162                 continue;
    163             }
    164             if(pd)
    165             {
    166                 for(int i=2;i<=n;i++)SUM_2suf[i]=b[i]-b[i-1];
    167                 LL tem=0;
    168                 for(int i=2;i<=n;i++)tem+=SUM_2suf[i];
    169                 tem+=b[1]*2;
    170                 SUM=tem/(n-1);
    171                 for(int i=2;i<=n;i++)suf[i]=(SUM-SUM_2suf[i])/2;
    172                 suf[1]=SUM;suf[n+1]=0;
    173                 for(int i=1;i<=n;i++)a[i]=suf[i]-suf[i+1];
    174                 for(int i=1;i<=n;i++)
    175                     printf("%lld ",a[i]);
    176                 puts("");
    177                 continue;
    178             }
    179             else
    180             {
    181                 dfs3(1,0);
    182                 for(int i=2;i<=n;i++)TSUM+=SUM_2sum[i];
    183                 TSUM+=b[1]*2;
    184                 SUM=TSUM/(n-1);
    185                 dfs4(1,0);
    186                 for(int i=1;i<=n;i++)
    187                     printf("%lld ",a[i]);
    188                 puts("");
    189                 continue;
    190             }
    191         }
    192     }
    193 }
    194 inline int read()
    195 {    
    196     int s=0;char a=getchar();
    197     while(a<'0'||a>'9')a=getchar();
    198     while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();}
    199     return s;
    200 }
    201 inline void add(int u,int v)
    202 {
    203     ++num_e;    
    204     u(num_e)=u;
    205     v(num_e)=v;
    206     n(num_e)=f(u);
    207     f(u)=num_e;
    208 }
    View Code
  • 相关阅读:
    [转]HSPICE软件的应用及常见问题解决
    Node.js基于Express框架搭建一个简单的注册登录Web功能
    Node.js开发Web后台服务
    mysql update 将一个表某字段设为另一个表某字段的值
    一个最简的Thinkphp3.2 操作Mongodb的例子
    MongoDB GUI( Robo 3T) Shell使用及操作
    Robomongo,Mongo可视化工具
    thinkphp mysql和mongodb 完美使用
    大型网站系统架构演化之路
    30个php操作redis常用方法代码例子
  • 原文地址:https://www.cnblogs.com/Al-Ca/p/11257657.html
Copyright © 2011-2022 走看看