Rikka with Mista
Problem Description
R i k k a Rikka Rikka is a fervent fan of J o J o ′ s JoJo's JoJo′s Bizarre Adventure. As the last episode of Golden Wind has been aired, R i k k a Rikka Rikka, with the help of Y u t a Yuta Yuta, sets up this problem to express the love to M i s t a Mista Mista.
M i s t a ′ s Mista's Mista′s lucky number is 4. Today, M i s t a Mista Mista wants to test his luck with n magic cards: For each card, there is a non-negative integer on each side. The two numbers on the i − t h i-th i−th card are w i w_i wi and 0 0 0.
Firstly, M i s t a Mista Mista puts these n n n cards to table one by one. For each card, the probability of the w i w_i wi side to be upward is 12 12 12, and these probabilities are independent with each other. As a result, there are n n n integers on the table. Mista then sums up all these integers and counts the number of 4 s 4s 4s in the decimal representation of this sum: He uses this result to measure his luckiness.
Since it’s possible for each side of each card to be upward, there are 2 n 2^n 2n possible states in total. You are required to calculate the sum of the results for all these situations.
Input
The first line of the input contains a single integer T ( 4 ≤ T ≤ 4 ) T(4\leq T\leq 4) T(4≤T≤4), the number of test cases.
For each test case, the first line contains a single integer n ( 4 ≤ n ≤ 40 ) n(4\leq n\leq 40) n(4≤n≤40), the number of the cards.
The second line contains n n n integers w 1 , … , w n ( 4 ≤ w i ≤ 44444444 ) w_1,…,w_n(4\leq w_i\leq 44444444) w1,…,wn(4≤wi≤44444444), the positive numbers on the cards.
Output
For each test case, output a single line with a single integer, the answer.
Hint
There are 44 4s in the sample input. Mista would like this sample input.
In the first test case, there is 1 state with the sum equal to 0; 4 states with the sum equal to 4; 6 states with the sum equal to 8; 4 states with the sum equal to 12 and 1 state with the sum equal to 16.
Therefore, there are only 4 situations with the result equal to 1 while on other cases, the result is 0. So the answer should be 4.
Sample Input
4
4
4 4 4 4
4
4 4 44 44
4
4 44 44 4444
4
444 44444 44444 4444444
Sample Output
4
10
24
38
Source
2019 Multi-University Training Contest 9
题意
- 就是给你
n
n
n个数,每个数可选可不选,所以一共有
2
n
2^n
2n的方案,设第
i
i
i个方案中所有数字的和
k
k
k的数位中
4
4
4的出现次数为
c
n
t
i
cnt_i
cnti,求
∑ i = 1 2 n c n t i \sum_{i=1}^{2^n}{cnt_i} i=1∑2ncnti
题解
- 首先很容易想到的无脑做法是先 m e e t i n m i d d l e meet\ in\ middle meet in middle将所有数分成两半分别暴力算出所有可能的 s u m l , s u m r sum_l,sum_r suml,sumr,然后考虑每一位算贡献,比如算第 i i i位时,先把所有的 s u m l sum_l suml与 s u m r sum_r sumr模上 1 0 i + 1 10^{i+1} 10i+1然后枚举 s u m l sum_l suml,在 s u m r sum_r sumr中找出区间 [ 4 × 1 0 i − s u m l , 5 ∗ 1 0 i − s u m l ) [4\times 10^i-suml,5*10^i-suml) [4×10i−suml,5∗10i−suml)内的数量加到 a n s ans ans里,还需要找出区间 [ 1 0 i + 1 + 4 × 1 0 i − s u m l , 1 0 i + 1 + 5 × 1 0 i − s u m l ) [10^{i+1}+4\times 10^i-suml,10^{i+1}+5\times10^i-suml) [10i+1+4×10i−suml,10i+1+5×10i−suml),这里酸的是进位后产生的 4 4 4,比如 7 + 7 7+7 7+7,对于找区间内的数,可能需要排序然后 l o w e r _ b o u n d lower\_bound lower_bound,所以时间复杂度 O ( T ∗ 10 ∗ 2 n 2 ∗ n 2 ) O(T*10*2^{\frac{n}{2}}*\frac{n}{2}) O(T∗10∗22n∗2n),而且常数巨大。。显然就炸了
- 容易想到 4 4 4的产生要么是加上进位后产生要么就是无低位进位相加产生,那么分类计算,对于每一个 s u m l sum_l suml,假设 s u m l , s u m r sum_l,sum_r suml,sumr是按照最低的 i i i位排好序,那么显然在统计的时候枚举 s u m l sum_l suml的话,可行的 s u m r sum_r sumr的 p o s pos pos是单调的,所以就可以 O ( 2 n ) O(2^n) O(2n)找出所有答案,对于按照最低的 i i i位排序,实际上就是从低位开始的基数排序过程
- 算法复杂度 O ( T × n × 2 n ) O(T\times n\times 2^n) O(T×n×2n)
代码
#pragma GCC optimize ("Ofast")
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+10;
struct node{
long long l,r;
};
vector<node> a,b,c[10],d[10];
int n,val[maxn];
void solve(int *a,int k,vector<node>&b)
{
for(int i=0;i<(1<<k);i++) {
long long s=0;
for(int j=0;j<k;j++) if(i&(1<<j)) s+=a[j];
b.push_back(node{s,0});
}
}
long long get_jin0(vector<node>&a,vector<node>&b,long long base) //处理没有进位的答案
{
int point=b.size()-1;long long ans=0;
for(int i=0;i<a.size();i++) {
while(point>=0&&a[i].r+b[point].r>=base) point--;
ans+=(point+1);
}
return ans;
}
long long get_jin1(vector<node>&a,vector<node>&b,long long base) //处理进位为1的使当前位为4的答案
{
int point=0;long long ans=0;
int siz=b.size();
for(int i=a.size()-1;i>=0;i--) {
while(point<=siz-1&&a[i].r+b[point].r<base) point++;
ans+=(b.size()-point);
}
return ans;
}
int main()
{
int t;scanf("%d",&t);
while(t--) {
a.clear();b.clear();
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&val[i]);
solve(val+1,n/2,a);
solve(val+1+n/2,n-(n/2),b);
long long base=1,ans=0;
for(int w=0;w<=8;w++) {
for(int i=0;i<10;i++) c[i].clear(),d[i].clear();
for(int i=0;i<a.size();i++) c[a[i].l%10].push_back(node{a[i].l/10,a[i].r});
for(int i=0;i<b.size();i++) d[b[i].l%10].push_back(node{b[i].l/10,b[i].r});
for(int i=0;i<10;i++) { //枚举左半边的和的当前位的数
int k1=(14-i)%10,k2=(13-i)%10; //求右半边对应的和的当前位的数,k1表示在不进位的情况下的值,k2表示在后面有进位的情况下的需要的值
ans+=get_jin0(c[i],d[k1],base)+get_jin1(c[i],d[k2],base);
}
int now=0;
for(int i=0;i<10;i++) for(int j=0;j<c[i].size();j++) a[now++]=node{c[i][j].l,c[i][j].r+i*base};
now=0;
for(int i=0;i<10;i++) for(int j=0;j<d[i].size();j++) b[now++]=node{d[i][j].l,d[i][j].r+i*base};
base*=10;
}
printf("%lld\n",ans);
}
}