題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=6682
題意:現在有n個數,你可以任意組合,問在所有的組合中,對每個組合求和,那麼總共含有多少個數字4。
解題心得:
- 看到最大爲,第一個反應肯定就是折半搜索,首先將所有的個數均分成兩半,並且分別將每一半的所有組合求和暴力枚舉出來,設存放在和中。接下來就可以枚舉中的每一個數設當前數爲,枚舉中的每個位數,然後可以直接在另一半中找有多少個可以和加起來變成,如等於時可以在另一邊找和十進制位相同時有多少個,第二種就是找加起來爲,例如爲,那麼可以在另一邊找和十進制位相同時有多少個。這個方法在枚舉和遍歷的位數的時候都還好,但是對於在中查找的時候就需要對不停的排序二分查找,但是如果直接二分查找或者怎麼弄常數都會非常大。
- 這個題還有一點就是使用基數排序,排序之後設和中的低位已經排序好了,假如這個時候在找第位會組成有多少個的時候可以直接分成中每個位和中的直接加起來變成或,以及中每個位和中的加起來加上第位的進位變成或。這裏爲什麼要這麼分呢,因爲這樣分雙方都是有序的數這樣就不需要二分查找,直接一次遍歷就行了,減小了複雜度。
- 這題的時間卡得有點緊,難受。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1e6+100;
struct Node {//r爲已經排好序的低位
ll l, r;
};
vector <Node> vel, ver;
vector <Node> butl[15], butr[15];
ll n, t, num[100];
void init() {
vel.clear();
ver.clear();
scanf("%lld", &n);
for(ll i=1;i<=n;i++) {
scanf("%lld", &num[i]);
}
for(ll i=0;i<(1<<(n/2));i++) {
ll sum = 0;
ll pos = 1;
for(ll j=1;j<=i;j<<=1) {
if(i&(j)) {
sum+=num[pos];
}
pos++;
}
vel.push_back({sum, 0});
}
for(ll i=0;i<(1<<(n - n/2));i++) {
ll sum = 0;
ll pos = n/2+1;
for(ll j=1;j<=i;j<<=1) {
if(i&(j)) {
sum+=num[pos];
}
pos++;
}
ver.push_back({sum, 0});
}
}
ll get_half_ans(vector <Node> &l, vector <Node> &r, ll base) {
ll pos = 1ll * r.size() - 1;
ll ans = 0;
for(ll i=0;i<l.size();i++) {
while(pos >= 0 && l[i].r + r[pos].r >= base) pos--;
ans += pos + 1;
}
return ans;
}
ll get_all_ans(vector <Node> &l, vector <Node> &r, ll base) {
ll pos = 0;
ll ans = 0;
for(ll i=1ll*l.size()-1;i>=0;i--) {
while(pos < r.size() && r[pos].r + l[i].r < base) pos++;
ans += r.size()-pos;
}
return ans;
}
int main() {
// freopen("1.in.txt", "r", stdin);
scanf("%lld", &t);
while(t--) {
init();
ll base = 1;
ll ans = 0;
for (ll k = 0; k <= 8; k++) {
for(ll i=0;i<vel.size();i++) {
Node x = vel[i];
ll w = x.l % 10;
butl[w].push_back({x.l / 10, x.r});
}
for (ll i=0;i<ver.size();i++) {
Node x = ver[i];
ll w = x.l % 10;
butr[w].push_back({x.l / 10, x.r});
}
for (ll i = 0; i <= 9; i++) {
ll x1 = (14 - i) % 10, x2 = (13 - i) % 10;
ans += get_half_ans(butl[i], butr[x1], base) + get_all_ans(butl[i], butr[x2], base);
}
ll Index = 0;
for (ll i = 0; i <= 9; i++)
for (ll j = 0; j < butl[i].size(); j++)
vel[Index++] = {butl[i][j].l, i * base + butl[i][j].r};
Index = 0;
for (ll i = 0; i <= 9; i++)
for (ll j = 0; j < butr[i].size(); j++)
ver[Index++] = {butr[i][j].l, i * base + butr[i][j].r};
for (ll i = 0; i <= 9; i++) butl[i].clear(), butr[i].clear();
base *= 10;
}
printf("%lld\n", ans);
}
return 0;
}