题意

给出n个数,取任意个数加一起,将和的十进制表达中 4 的个数加到答案,问这 2 n 2^n 2n个和的4的个数的和

题解

分别计算 4 × 1 0 i 4\times10^i 4×10i 的答案
将一半的数放在A 中,另一半放在 B 中,分别暴力出所有组合
( A i + B j ) <mtext>   </mtext> m o d <mtext>   </mtext> 1 0 i + 1 [ 4 × 1 0 i , 5 × 1 0 i ) (A_i+B_j) ~mod~10^{i+1}\in[4\times10^i,5\times10^i) (Ai+Bj) mod 10i+1[4×10i,5×10i)时,答案加一
维持 A、B是有序的,所以可以用两个指针维护合法的区间
假设枚举的数字为 x x x, 算出合法区间 [ n , m ] [n,m] [n,m] ,然后让 l l l 指向 n \geq n n的第一个数, r r r 指向 m \geq m m 的第一个数,那么 r l r-l rl 就是答案
值得注意的是, r l r-l rl 可能产生负数,我们规定,所有的位置都是在 m o d <mtext>   </mtext> l e n g h ( B ) mod ~lengh(B) mod lengh(B) 的意义下的,所以负数加上
l e n g t h ( B ) length(B) length(B) 就可以了,基于此,所有的数组下标从 0 0 0 开始,真的方便了好多

然后是如何维护有序
用归并排序就好了
因为,一开始要排次序,这就保证了对应位相同的数,他的下一位也是有序的,如此,满足归并排序的条件
自带 i n p l a c e _ m e r g e ( f i r s t , s e c o n d , l a s t ) inplace\_merge(first,second,last) inplace_merge(first,second,last) 函数

代码

#include<bits/stdc++.h>
#define N (1<<20)+3
#define LL long long
#define sc(x) scanf("%d",&x)
using namespace std;

int w[N],T,n,m,a,b,tot,l,r; 
int A[N],B[N],p4[10],p5[10],d[11],p[10];
int *c;
LL ans;

void dfs(int x,int y,int z){
    if (x==y){
        c[tot++]=z;
        return;
    }
    dfs(x+1,y,z+w[x]);
    dfs(x+1,y,z);
}

void merge(int *C,int c,int x){
    for(int i=0;i<11;i++) d[i]=c;
    for(int i=0;i<c;i++){
        int t=C[i]/p[x];
        if (d[t]==c) d[t]=i;
        C[i]%=p[x];
    }
    for(int i=9;i>=0;i--) if (d[i]==c) d[i]=d[i+1];
    for(int i=0;i<9;i++)
        inplace_merge(C,C+d[i+1],C+d[i+2]);
}

inline void mantain(int y,int x){
    int n=p4[x]-y,m=p5[x]-y-1;
    if (n<0) n+=p[x-1];
    if (m<0) m+=p[x-1];
    while(l<b&&B[l]<n) l++;
    while(l&&B[l-1]>=n) l--;
    while(r<b&&B[r]<=m) r++;
    while(r&&B[r-1]>m) r--;
}

void work(int x){
    l=r=0;
    for(int i=0;i<a;i++){
        mantain(A[i],x);
        ans+=r-l;
        if(r-l<0) ans+=b;
    }
    merge(A,a,x);
    merge(B,b,x);
}

int main(int argc, char const *argv[]){
    sc(T);
    while(T--){
        sc(n);
        for(int i=0;i<n;i++) sc(w[i]);
        
        c=A; tot=0; dfs(0,n/2,0); a=tot;
        c=B; tot=0; dfs(n/2,n,0); b=tot;

        sort(A,A+a); sort(B,B+b);

        ans=0;
        p[9]=1; for(int i=8;i>=0;i--) p[i]=p[i+1]*10;
        for(int i=1;i<10;i++) p4[i]=p[i]*4,p5[i]=p[i]*5;
        for(int i=1;i<10;i++) work(i);
        printf("%lld\n",ans);
    }
    return 0;
}