• pkuwc2018题解


    题解:

    思路挺好想的。。然而今天写代码写成傻逼了

    d1t1:

    首先比较暴力的就是$f[i][j]$表示i个这个点是j的概率

    然后前缀和一下dp就是$n^2$的

    部分分树形态随机就说明树深度是$log$的

    只转移子树中有的点,复杂度$nlogn$的

    正解也很好想

    我们化简一下那个式子(早上的草稿纸找不到了。。)

    反正形如$(ai*sum[i]+bi)*pi$

    因为最多只有两个儿子,显然启发式合并或者线段树合并可以维护这个sum[i]然后复杂度是$nlogn$的

    30min写完一下过了样例一交爆0

    然后就debug了无限久

    大概先是通过手造发现要先做左二子,然后发现了查询没down

    然后手造就再也发现不了问题

    就改对拍(早知道就早点写了)

    然后那个数据要在不太能手摸的时候才出错。。

    找了半天才发现是merge里面没有把y的sum加到x上

    然后交了tle70

    然后我把map改了hash快了一点点还是70

    于是又离散化才过

    于是我写了2个半小时这题 简直是傻逼

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for (int i=h;i<=t;i++)
    #define dep(i,t,h) for (int i=t;i>=h;i--)
    #define me(x) memset(x,0,sizeof(x))
    #define ll long long
    #define mid ((h+t)>>1)
    namespace IO
    {
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T>void read(T &x)
        {
            rint f=1,c;while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f;
        }
        char sr[1<<24],z[20]; int C=-1,Z;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C]='-',x=-x; 
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C]=z[Z],--Z);
        }
        IL void wer1() {sr[++C]=' ';}
        IL void wer2() {sr[++C]='
    ';}
        template<class T>IL void maxa(T &x,T y) { if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) { if (x>y) x=y;}
        template<class T>IL T MAX(T x,T y){ return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){ return x<y?x:y;}
    }
    using namespace IO;
    const int N=4e5;
    const int M2=N*30;
    const int mo=998244353;
    const int INF=4e5;
    int ch[N][2],cnt[N],v[N];
    const int mo2=1e7+7;
    struct Hash{
        int a[mo2+1000],b[mo2+1000];
        IL void push(int x,int y)
        {
            int pos=x%mo2;
            while (a[pos]&&a[pos]!=x) pos++;
            a[pos]=x; b[pos]=y;
        }
        IL int find(int x)
        {
            int pos=x%mo2;
            while (a[pos]&&a[pos]!=x) pos++;
            return b[pos];
        }
    }H;
    IL int fsp(int x,int y)
    {
        ll now=1;
        while (y)
        {
            if (y&1) now=now*x%mo;
            x=1ll*x*x%mo; y>>=1;
        }
        return now;
    }
    int rt[N];
    map<int,int> M;
    struct re{
        int a,b;
    }p[N];
    int tf;
    struct sgt{
        int sum[M2],lazy[M2],ls[M2],rs[M2],cnt2;
        sgt() { rep(i,0,M2-1) lazy[i]=1;}
        IL void down(int x)
        {
            if (lazy[x]!=1)
            {
                sum[ls[x]]=1ll*sum[ls[x]]*lazy[x]%mo;
                sum[rs[x]]=1ll*sum[rs[x]]*lazy[x]%mo;
                lazy[ls[x]]=1ll*lazy[ls[x]]*lazy[x]%mo;
                lazy[rs[x]]=1ll*lazy[rs[x]]*lazy[x]%mo;
                lazy[x]=1;
            }
        }
        int merge(int x,int y,int p1,int p2,int p)
        {
            down(x); down(y);
            if (!x&&!y) return 0;
            if (!x)
            {
                lazy[y]=(1ll*p1*(2*p-1)+(1-p))%mo;
                sum[y]=1ll*lazy[y]*sum[y]%mo;
                return y;
            }
            if (!y)
            {
                lazy[x]=(1ll*p2*(2*p-1)+(1-p))%mo;
                sum[x]=1ll*sum[x]*lazy[x]%mo;
                return x;
            }
            rs[x]=merge(rs[x],rs[y],(p1+sum[ls[x]])%mo,(p2+sum[ls[y]])%mo,p);
            ls[x]=merge(ls[x],ls[y],p1,p2,p);
            sum[x]=(sum[ls[x]]+sum[rs[x]])%mo;
            return x;
        }
        void change(int &x,int h,int t,int pos)
        {
            x=++cnt2; sum[x]=1;
            if (h==t) return;
            if (pos<=mid) change(ls[x],h,mid,pos);
            else change(rs[x],mid+1,t,pos);
        }
        int query(int x,int h,int t)
        {
            if (!x) return(0);
            if (h==t)
            {
              return 1ll*h*p[h].a%mo*sum[x]%mo*sum[x]%mo;
            }
            down(x);
            return (query(ls[x],h,mid)+query(rs[x],mid+1,t))%mo;
        }
    }S;
    void dfs(int x)
    {
        if (!x) return;
        if (cnt[x]==2)
        {
          dfs(ch[x][0]); dfs(ch[x][1]);
          rt[x]=S.merge(rt[ch[x][0]],rt[ch[x][1]],0,0,v[x]);
        } else if (cnt[x]==1)
        {
          dfs(ch[x][0]);
          rt[x]=rt[ch[x][0]];
        } else
        {
            S.change(rt[x],1,INF,v[x]);
        }
    }
    int n;
    bool cmp(re x,re y)
    {
        return x.a<y.a;
    }
    int main()
    {
        read(n);
        rep(i,1,n)
        {
          int x;
          read(x);
          ch[x][cnt[x]++]=i;
        }
        int ni10000=fsp(10000,mo-2),num=0;
        rep(i,1,n)
        { 
          read(v[i]);
          if (cnt[i]) v[i]=1ll*v[i]*ni10000%mo;
          else p[++num]=(re){v[i],i};
        }  
        sort(p+1,p+num+1,cmp);
        rep(i,1,num) v[p[i].b]=i;
      //  rep(i,1,num) H.push(p[i],i);
        dfs(1);
        cout<<S.query(rt[1],1,INF)<<endl;
        return 0;
    }
    View Code

    d1t2:

    (我的做法可能比较麻烦常数比别人大2-3倍)

    这个贪心的性质非常明显,有强化卡肯定强化他然后选最大的(没有当然只能选攻击了)

    看数据范围就知道这个东西很明显是$n^2$的 并且不能带$log$

    于是这时候很明显是dp了

    对于强化卡我们$f[i][j]$表示前i张选j张不同方案的乘积和(注意如果>k-1只取k-1张) 所以要先排序

    那对于攻击卡我们怎么选择呢,似乎暴力$dp$需要$f[i][j][k]$,i张里面选j张,使用k张攻击卡

    但我们排序后发现,对后面的我们可以直接乘组合数

    于是处理出$f[i][j]$表示前i张选j张并且攻击了

    最后枚举$i$和强化卡使用数量num,那么j就是$max(1,k-num)$,再乘个组合数就好了

    刚开始第二个样例wa了

    写了个拍查了一下就对了

    然后提交上去30?????

    卧槽卡常这么恐怖的么

    然后就是30-40-60-100了

    (大概是 把多次调用数组同一个值的地方改掉了 上下界修改了一下 MAX只调用一次 C数组改变了一下两维的顺序)

    连续两天用指针卡常发现没用

    以后再也不改指针了,最花时间又最没用的卡常

    当然这些都改了也只有60

    通过删减代码发现时间在最后统计处

    然后用常用的套路去减少取模次数

    于是我循环展开了然后4次取模一次(8次测出来和4次效果差不多)

    终于过了

    我也不知道为啥这个常数这么大。。。跟正解好像没啥区别。。。

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for (int i=h;i<=t;i++)
    #define dep(i,t,h) for (int i=t;i>=h;i--)
    #define me(x) memset(x,0,sizeof(x))
    #define ll long long
    #define mid ((h+t)>>1)
    namespace IO
    {
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T>void read(T &x)
        {
            rint f=1,c;while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f;
        }
        char sr[1<<24],z[20]; int C1=-1,Z;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C1]='-',x=-x; 
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C1]=z[Z],--Z);
        }
        IL void wer1() {sr[++C1]=' ';}
        IL void wer2() {sr[++C1]='
    ';}
        template<class T>IL void maxa(T &x,T y) { if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) { if (x>y) x=y;}
        template<class T>IL T MAX(T x,T y){ return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){ return x<y?x:y;}
    }
    using namespace IO;
    const int N=4e3;
    const int mo=998244353;
    int w1[N],w2[N];
    int f1[N][N],f2[N][N],C[N][N],g[N][N],C2[N][N],f3[N][N];
    bool cmp(int x,int y)
    {
        return x>y;
    }
    int main()
    {
        int T;
        read(T);
        rep(i,0,3100)
        {
          rep(j,1,i)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mo;
          C[i][0]=1;
        }
        rep(i,0,3100)
          rep(j,0,3100)
            C2[i][j]=C[j][i]; 
        while (T--)
        {
            int n,m,k;
            read(n); read(m); read(k);
            rep(i,1,n) read(w1[i]);
            rep(i,1,n) read(w2[i]);
            sort(w1+1,w1+n+1,cmp); sort(w2+1,w2+n+1,cmp);
            f1[0][0]=0; f2[0][0]=0;
            rep(i,0,n) f1[i][0]=1;
            rep(i,1,n)
            {
              int t=MIN(i,m);
              rep(j,1,t)
              {
                if (j<k) f1[i][j]=(f1[i-1][j]+1ll*f1[i-1][j-1]*w1[i])%mo;
                else f1[i][j]=(f1[i-1][j]+f1[i-1][j-1])%mo;
              }
            }
            rep(i,1,n)
            {
              int t=MIN(i,m);
              rep(j,1,t)
              {
                  f2[i][j]=(g[i-1][j-1]+1ll*w2[i]*C[i-1][j-1])%mo;
                  g[i][j]=(g[i-1][j-1]+g[i-1][j]+1ll*w2[i]*C[i-1][j-1])%mo;
              }
            }
            unsigned ll ans=0;
            for (register int j=0;j<=n;j++)
            {
              int tt=MAX(k-j,1),tt1=f1[n][j];
              int *pp=C2[m-j-tt];
              register int i;
              for (i=1;i+8<=n;i+=8)
              {
                ans+=1ll*tt1*f2[i][tt]%mo*pp[n-i];
                ans+=1ll*tt1*f2[i+1][tt]%mo*pp[n-i-1];
                ans+=1ll*tt1*f2[i+2][tt]%mo*pp[n-i-2];
                ans+=1ll*tt1*f2[i+3][tt]%mo*pp[n-i-3]; 
                ans+=1ll*tt1*f2[i+4][tt]%mo*pp[n-i-4];
                ans+=1ll*tt1*f2[i+5][tt]%mo*pp[n-i-5];
                ans+=1ll*tt1*f2[i+6][tt]%mo*pp[n-i-6];
                ans+=1ll*tt1*f2[i+7][tt]%mo*pp[n-i-7];
                ans%=mo;
              }
              for(;i<=n;i++)
               ans+=1ll*tt1*f2[i][tt]%mo*pp[n-i];
              ans%=mo;
            }
            wer(ans); wer2();
        }
        fwrite(sr,1,C1+1,stdout);
        return 0;
    }
    View Code

     

    d1t3:
    果然是不可做题。。再见

    d2t1:

    因为记得我看过游记说这个是道傻逼题

    于是看了题目10min写了个next_permutation然后拿了10分

    我才意识到把排序当2^n了

    然后就先去写了一道lct

    写完重新开始想。。感觉已经晕了

    然后我就很zz的想出了$nlog^3n$的做法

    然后发现这个东西常数极小就写了

    大概就是$f[i][j]$表示当前状态中有i这些点,然后与它相连的点有j个(包括自己)

    然后转移就可以枚举现在放了几个点在后面

    然后挺好写

    不过拍了一下发现我把$A()$搞成了$x!$ 改了就拍上了

    交了之后发现数组开小了

    然后并不是很理解为啥这个数组要40

    后来发现我把自己重复计数了( 我也不懂为什么这都是对的)

    果然跑的飞快

    也就是$nlogn$慢了3倍

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for (int i=h;i<=t;i++)
    #define dep(i,t,h) for (int i=t;i>=h;i--)
    #define me(x) memset(x,0,sizeof(x))
    #define ll long long
    #define mid ((h+t)>>1)
    namespace IO
    {
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T>void read(T &x)
        {
            rint f=1,c;while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f;
        }
        char sr[1<<24],z[20]; int C=-1,Z;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C]='-',x=-x; 
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C]=z[Z],--Z);
        }
        IL void wer1() {sr[++C]=' ';}
        IL void wer2() {sr[++C]='
    ';}
        template<class T>IL void maxa(T &x,T y) { if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) { if (x>y) x=y;}
        template<class T>IL T MAX(T x,T y){ return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){ return x<y?x:y;}
    }
    using namespace IO;
    const int N=1.5e6;
    const int M=25;
    #define lowbit(x) (x&(-x))
    bool f[50][N],o[N];
    int g[N][50];
    int a[N],num,ans1[N],ans2[N],jc[60],jc2[60];
    const int mo=998244353;
    IL int fsp(int x,int y)
    {
        ll now=1;
        while (y)
        {
            if (y&1) now=now*x%mo;
            x=1ll*x*x%mo; y>>=1;
        }
        return now;
    }
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        int n,m;
        read(n); read(m);
        rep(i,1,m)
        {
            int x,y;
            read(x); read(y);
            f[y][1<<(x-1)]=1;
            f[x][1<<(y-1)]=1;
        }
        jc[0]=1; jc2[0]=1;
        rep(i,1,40) jc[i]=1ll*jc[i-1]*i%mo,jc2[i]=fsp(jc[i],mo-2);
        rep(i,1,n)
          rep(j,1,(1<<n)-1)
            f[i][j]=f[i][j-lowbit(j)]|f[i][lowbit(j)];
        rep(j,1,(1<<n)-1)
          rep(i,1,n)
          { 
            if (f[i][j]||(j>>(i-1))&1) ans1[j]++;
            if ((j>>(i-1))&1) ans2[j]++;
          }
        g[0][0]=1;
        rep(i,0,(1<<n)-1)
          rep(j,ans2[i],ans1[i])
            if (g[i][j])
            {
                if (j>=25) cout<<"sb"<<endl;
                rep(k,1,n)
                  if (!((i>>(k-1))&1)&&!f[k][i])
                  {
                      o[i|(1<<(k-1))]=1;
                      int pu=ans1[i|(1<<(k-1))];
                    rep(i1,j+1,pu)
                    {
                      if (i1>=25) cout<<(i|(1<<(k-1)))<<endl;
                      g[i|(1<<(k-1))][i1]=(g[i|(1<<(k-1))][i1]+1ll*g[i][j]*jc[pu-j-1]%mo*jc2[pu-i1])%mo;
                    }
                  }
            }
        int cnt=0;
        dep(i,(1<<n)-1,1) 
          if (o[i])
          {
              maxa(cnt,ans2[i]);
          }
        ll ans=0;
        rep(i,1,(1<<n)-1)
          if (ans2[i]==cnt) (ans+=g[i][n])%=mo;
        ll ans3=1;
        rep(i,1,n) ans3=ans3*i%mo;
        cout<<ans*fsp(ans3,mo-2)%mo<<endl;
        return 0;
    }
    View Code

    正解是这样的:

    大概就是跟我反着记录

    $f[i][j]$表示当前有状态i内的点不能经过,独立集内有j个点的方案

    然后现在枚举加入一个点会带来k个不合法的,就把他们插入到剩下的位置就可以了

    这样是$2^n*n^2$的

    然后这么dp的话显然是$i$相同时j越大越好且一定好于j小的

    所以记录一下最大就行了

    复杂度$nlogn$

    我那个方法完全没法优化理论复杂度。。

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for (int i=h;i<=t;i++)
    #define dep(i,t,h) for (int i=t;i>=h;i--)
    #define me(x) memset(x,0,sizeof(x))
    #define ll long long
    #define mid ((h+t)>>1)
    namespace IO
    {
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T>void read(T &x)
        {
            rint f=1,c;while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f;
        }
        char sr[1<<24],z[20]; int C=-1,Z;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C]='-',x=-x; 
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C]=z[Z],--Z);
        }
        IL void wer1() {sr[++C]=' ';}
        IL void wer2() {sr[++C]='
    ';}
        template<class T>IL void maxa(T &x,T y) { if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) { if (x>y) x=y;}
        template<class T>IL T MAX(T x,T y){ return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){ return x<y?x:y;}
    }
    using namespace IO;
    const int N=1.5e6;
    const int M=25;
    #define lowbit(x) (x&(-x))
    bool f[50][N],o[N];
    int g[N][50];
    int a[N],num,ans1[N],ans2[N],jc[60],jc2[60];
    const int mo=998244353;
    IL int fsp(int x,int y)
    {
        ll now=1;
        while (y)
        {
            if (y&1) now=now*x%mo;
            x=1ll*x*x%mo; y>>=1;
        }
        return now;
    }
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        int n,m;
        read(n); read(m);
        rep(i,1,m)
        {
            int x,y;
            read(x); read(y);
            f[y][1<<(x-1)]=1;
            f[x][1<<(y-1)]=1;
        }
        jc[0]=1; jc2[0]=1;
        rep(i,1,40) jc[i]=1ll*jc[i-1]*i%mo,jc2[i]=fsp(jc[i],mo-2);
        rep(i,1,n)
          rep(j,1,(1<<n)-1)
            f[i][j]=f[i][j-lowbit(j)]|f[i][lowbit(j)];
        rep(j,1,(1<<n)-1)
          rep(i,1,n)
          { 
            if (f[i][j]||(j>>(i-1))&1) ans1[j]++;
            if ((j>>(i-1))&1) ans2[j]++;
          }
        g[0][0]=1;
        rep(i,0,(1<<n)-1)
          rep(j,ans2[i],ans1[i])
            if (g[i][j])
            {
                if (j>=25) cout<<"sb"<<endl;
                rep(k,1,n)
                  if (!((i>>(k-1))&1)&&!f[k][i])
                  {
                      o[i|(1<<(k-1))]=1;
                      int pu=ans1[i|(1<<(k-1))];
                    rep(i1,j+1,pu)
                    {
                      if (i1>=25) cout<<(i|(1<<(k-1)))<<endl;
                      g[i|(1<<(k-1))][i1]=(g[i|(1<<(k-1))][i1]+1ll*g[i][j]*jc[pu-j-1]%mo*jc2[pu-i1])%mo;
                    }
                  }
            }
        int cnt=0;
        dep(i,(1<<n)-1,1) 
          if (o[i])
          {
              maxa(cnt,ans2[i]);
          }
        ll ans=0;
        rep(i,1,(1<<n)-1)
          if (ans2[i]==cnt) (ans+=g[i][n])%=mo;
        ll ans3=1;
        rep(i,1,n) ans3=ans3*i%mo;
        cout<<ans*fsp(ans3,mo-2)%mo<<endl;
        return 0;
    }
    View Code

    d2t2:

    d2t3:

  • 相关阅读:
    【服务器】Https服务配置
    【小程序】模拟请求加载数据(本地数据(无服务器))
    BlockingQueue深入解析
    通过maven下载源码和javadoc方法
    运维随笔
    Linux的虚拟内存管理-如何分配和释放内存,以提高服务器在高并发情况下的性能,从而降低了系统的负载
    java写卷积神经网络---CupCnn简介
    使用tcmalloc替换系统的malloc
    Java 进程占用 VIRT 虚拟内存超高的问题研究
    Java8 jvm参数
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/10151240.html
Copyright © 2020-2023  润新知