6682 Rikka with Mista
题意:给定n个元素,共有
2
n
2^n
2n个子集,求所有子集和中4的个数的和
分析:折半搜索+双指针查找+按位算贡献+桶排序
const int maxn = 40+1,maxm= 1048576+10;
LL f[10][maxm];// 桶排序
LL num[2][maxm];//
LL num1[2][maxm];
LL w[maxn];
int n,n1,n2;
void dfs(int x,int t,int n,LL val,int &cnt){
if(x ==n+1){
num[t][++cnt] = val;
return ;
}
dfs(x+1,t,n,val,cnt);
dfs(x+1,t,n,val+w[x],cnt);
}
bool cmp(const LL &a,const LL &b){
return a%10 < b%10;
}
void Sort(LL *a,int n,LL t,int sign){
// DEBUG;
for(int i =0;i < 10; ++i)
f[i][0] =0;
for(int i = 1;i <= n; ++i){
LL tmp = num[sign][i]%(t*10)/t;
f[tmp][++f[tmp][0]] = num[sign][i];
}
// DEBUG;
int tmp = 0;
for(int i = 0;i <= 9; ++i){
for(int j = 1;j <= f[i][0]; ++j){
// cout<<t<<endl;
// cout<<tmp<<endl;
num[sign][++tmp] = f[i][j];
}
}
// DEBUG;
if(sign == 0)
assert(tmp == n1);
if(sign == 1)
assert(tmp == n2);
}
int main(void)
{
// freopen("test.in","r",stdin);
int T;cin>>T;
// cout<<T<<endl;
while(T--){
cin>>n;
for(int i = 1;i <= n; ++i)
scanf("%lld",&w[i]);
dfs(1,0,n/2,0,n1=0);
dfs(n/2+1,1,n,0,n2=0);
assert(n1 == (1<<n/2));
assert(n2 == (1<<(n-n/2)));
// DEBUG;
sort(num[0]+1,num[0]+n1+1,cmp);
sort(num[1]+1,num[1]+n2+1,cmp);
// DEBUG;
LL t = 1;
LL ans = 0;
for(int i =0;i <= 9; ++i){
LL t4 = 4*t;
LL t5 = 5*t;
LL t14 = t4+10*t;
LL t15 = t5+10*t;
// DEBUG;
t *= 10;
for(int j = 1;j <= n1; ++j)
num1[0][j] = num[0][j]%t;
for(int j = 1;j <= n2; ++j)
num1[1][j] = num[1][j]%t;
// for(int j = 1;j <= n1; ++j){
// cout<<num1[1][j]<<" ";
// }
// cout<<endl;
int l = n2+1,r =n2+1;
num1[1][n2+1] = INFF;
for(int j = 1;j <= n1; ++j){
while(r >= 1&&num1[1][r] >= t5-num1[0][j]) r--;
while(l >= 1&&num1[1][l] >= t4-num1[0][j]) l--;
ans += r-l;
// ans +=lower_bound(num1[1]+1,num1[1]+n2+1,t5-num1[0][j])- lower_bound(num1[1]+1,num1[1]+n2+1,t4-num1[0][j]);
// ans +=lower_bound(num1[1]+1,num1[1]+n2+1,t15-num1[0][j])- lower_bound(num1[1]+1,num1[1]+n2+1,t14-num1[0][j]);
}
l = n2+1,r =n2+1;
for(int j = 1;j <= n1; ++j){
while(r >= 1&&num1[1][r] >= t15-num1[0][j]) r--;
while(l >= 1&&num1[1][l] >= t14-num1[0][j]) l--;
ans += r-l;
// ans +=lower_bound(num1[1]+1,num1[1]+n2+1,t5-num1[0][j])- lower_bound(num1[1]+1,num1[1]+n2+1,t4-num1[0][j]);
// ans +=lower_bound(num1[1]+1,num1[1]+n2+1,t15-num1[0][j])- lower_bound(num1[1]+1,num1[1]+n2+1,t14-num1[0][j]);
}
// cout<<ans<<endl;
// DEBUG;
Sort(num[0],n1,t,0);
Sort(num[1],n2,t,1);
}
cout<<ans<<endl;
}
return 0;
}
/*
1
4
4 44 44 4444
4
444 44444 44444 4444444
*/