[题解] NOI Online #3 优秀子序列

Luogu P6570

\(n\) 为值域。

首先有个 \(\mathcal O(3^{\log_2n}) = \mathcal O(n ^ {1.5})\) 的子集 DP。

式子很像子集卷积,但如果把每个数依次卷起来复杂度过高,不可接受。

考虑分组,发现有相同一个二进制位的数必然不会被卷到一起。

但如果按照一般二进制位分成 \(\log n\) 组,再依次卷积,复杂度是 \(\mathcal O(n \log^3 n)\),其中每次卷积是 \(\mathcal O(n \log^2 n)\)

考虑限制每组元素的个数,按照最高位分组,这样每组的二进制长度受到限制 ,复杂度就会为:

\[\sum_{i=1}^{\log n} 2^i \cdot i^2 = \mathcal O(n \log^2 n) \]

其中 \(i\) 为每组的长度。

Code

当然可以继续压常数

#include <cstdio>
#include <algorithm>
using namespace std;
#define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
typedef long long ll;
namespace io {
  const int SIZE = (1 << 21) + 1;
  char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
  #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
  char getc () {return gc();}
  inline void flush () {fwrite (obuf, 1, oS - obuf, stdout); oS = obuf;}
  inline void putc (char x) {*oS ++ = x; if (oS == oT) flush ();}
  template <class I> inline void gi (I &x) {for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;}
  template <class I> inline void print (I x) {if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;while (x) qu[++ qr] = x % 10 + '0',  x /= 10;while (qr) putc (qu[qr --]);}
  struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: gi; using io :: putc; using io :: print; using io :: getc;
template<class T> void upmax(T &x, T y){x = x>y ? x : y;}
template<class T> void upmin(T &x, T y){x = x<y ? x : y;}

const int N = 262144;
const int mod = 1000000007;
int phi[N + 1], p[N + 1], pc = 0;
bool np[N + 1];

inline int add(int x, int y) {return x+y>=mod ? x+y-mod : x+y;}
inline int sub(int x, int y) {return x-y<0 ? x-y+mod : x-y;}
inline int mul(int x, int y) {return 1LL * x * y % mod;}
inline void inc(int &x, int y=1) {x += y; if(x >= mod) x -= mod;}
inline void dec(int &x, int y=1) {x -= y; if(x < 0) x += mod;}
inline int power(int x, int y){
  int res = 1;
  for(; y; y>>=1, x = mul(x, x)) if(y & 1) res = mul(res, x);
  return res;
}
inline int inv(int x){return power(x, mod - 2);}

void getPhi(int n){
  phi[1] = 1;
  for(int i=2; i<=n; i++){
    if(!np[i]) p[++pc] = i, phi[i] = i - 1;
    for(int j=1; j<=pc && i * p[j] <= n; j++){
      np[i * p[j]] = true;
      if(i % p[j] == 0){
        phi[i * p[j]] = phi[i] * p[j];
        break;
      }
      phi[i * p[j]] = phi[i] * (p[j] - 1);
    }
  }
}

void FWT(int a[], int len){
  for(int w=2, k=1; w<=len; w<<=1, k<<=1)
    for(int i=0; i!=len; i+=w)
      for(int j=i, li=i+k; j!=li; ++j)
        inc(a[j + k], a[j]);
}
void IFWT(int a[], int len){
  for(int w=2, k=1; w<=len; w<<=1, k<<=1)
    for(int i=0; i!=len; i+=w)
      for(int j=i, li=i+k; j!=li; ++j)
        dec(a[j + k], a[j]);
}
void subsetConv(int a[], int b[], int c[], int len){
  static int popc[N];
  static int A[19][N], B[19][N], C[19][N];
  for(int i=0; i<len; i++){
    popc[i] = popc[i >> 1] + (i & 1);
    A[popc[i]][i] = a[i];
    B[popc[i]][i] = b[i];
  }
  int n = popc[len - 1];
  for(int i=0; i<n; i++){
    FWT(A[i], len);
    FWT(B[i], len);
  }
  for(int k=0; k<=n; k++)
    for(int i=0; i<=k; i++)
      for(int p=0; p<len; p++)
        inc(C[k][p], mul(A[i][p], B[k - i][p]));
  for(int i=0; i<=n; i++) IFWT(C[i], len);
  for(int i=0; i<len; i++) c[i] = C[popc[i]][i];
  for(int i=0; i<=n; i++){
    fill_n(A[i], len, 0);
    fill_n(B[i], len, 0);
    fill_n(C[i], len, 0);
  }
}

int cnt[N];
int a[19][N], num[N];

int main(){
  getPhi(262144);
  int n;
  gi(n);

  static int high[N];
  for(int i=1; i<262144; i++)
    high[i] = high[i >> 1] + 1;
  int bit = 0;
  for(int i=0; i<n; i++){
    int x; gi(x);
    ++a[high[x]][x];
    upmax(bit, high[x]);
  }
  static int s[N];
  s[0] = power(2, a[0][0]);
  s[1] = mul(s[0], a[1][1]);
  for(int i=2; i<=bit; i++){
    a[i][0] = 1;
    subsetConv(s, a[i], s, 1 << i);
  }

  int sum = 0;
  for(int i=0; i<(1 << bit); i++)
    inc(sum, mul(phi[i + 1], s[i]));
  print(sum); putc('\n');
  return 0;
}
posted @ 2020-06-07 10:12  RiverHamster  阅读(166)  评论(0编辑  收藏  举报
\