We have NN integers A1,A2,...,ANA1,A2,...,AN.ios
There are N(N−1)2N(N−1)2 ways to choose two of them and form a pair. If we compute the product of each of those pairs and sort the results in ascending order, what will be the KK-th number in that list?数组
给定一个含有n个整数的数组a,将其全部点对$(i,j),i \neq j$,两两相乘$a[i]*a[j]$ 获得$\frac{N(N-1)}{2}$个数,问将其升序排序后第k个数是多少?dom
将$a[i]$ 分为3类:大于0,等于0,小于0。分别加入vector容器 v1,v0,v2中后排序容器。函数
而后再$[-1e18,1e18]$ 中二分答案ans,this
而后以时间复杂度为$O(n*log_2(n))$ 的方法去计算有多少对数相乘小于ans,方法为:spa
若是ans小于0:code
只须要遍历v1中的每个元素y,而后二分找到v2中与y相乘小于ans的下标,而后更新计数。orm
若是ans等于0:排序
小于ans的必定是负数,那么只有正数与负数相乘才会获得负数,因此计数=$v1.size()*v2.size()$ip
若是ans大于0:
负数和零必定小于ans,因此计数先加上$v1.size()v2.size()+v0.size()(v1.size()+v2.size())$
而后再找正数中小于ans的乘积对:
遍历v1中的每个元素y,而后二分找到v1中与y相乘小于ans的下标,更新计数。
遍历v2中的每个元素y,而后二分找到v2中与y相乘小于ans的下标,更新计数。
对于vector容器的二分咱们可使用lower_bound()和upper_bound() 两个函数。
二分过程当中可能会用到$ceil(\frac{x}{y})= \left \lceil \frac{x}{y} \right \rceil=\frac{x+y-1}{y}$,能够避免精度丢失引发的偏差。
具体能够看代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #define ALL(x) (x).begin(), (x).end() #define sz(a) int(a.size()) #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl #define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c)) #define du2(a,b) scanf("%d %d",&(a),&(b)) #define du1(a) scanf("%d",&(a)); using namespace std; typedef long long ll; ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} ll lcm(ll a, ll b) {return a / gcd(a, b) * b;} ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;} void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;} inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;} const int maxn = 1000010; const int inf = 0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ ll k, n; ll a[maxn]; std::vector<ll> v1, v2; ll len1, len2; std::vector<ll> v; ll cnt = 0ll; bool check(ll x) { ll res = 0ll; if (x > 0) { for (auto y : v1) { res += lower_bound(ALL(v), (x + y - 1) / y) - v.begin(); v.push_back(y); } v.clear(); for (auto y : v2) { res += lower_bound(ALL(v), (x + y - 1) / y) - v.begin(); v.push_back(y); } v.clear(); res += cnt * (cnt - 1) / 2; res += 1ll * sz(v1) * sz(v2); res += cnt * (sz(v1) + sz(v2)); } else if (x < 0) { x = -x; for (auto y : v1) { res += sz(v2) - (upper_bound(ALL(v2), x / y) - v2.begin()); } } else { res += 1ll * sz(v1) * sz(v2); } return res < k; } int main() { //freopen("D:\\code\\text\\input.txt","r",stdin); //freopen("D:\\code\\text\\output.txt","w",stdout); n = readll(); k = readll(); repd(i, 1, n) { a[i] = readll(); if (a[i] > 0) { v1.push_back(a[i]); } else if (a[i] < 0) { v2.push_back(-a[i]); } else { cnt++; } } sort(ALL(v1)); sort(ALL(v2)); len1 = sz(v1); len2 = sz(v2); ll l = -1e18; ll r = 1e18; ll mid; ll ans; while (l <= r) { mid = (l + r) >> 1; if (check(mid)) { l = mid + 1; ans = mid; } else { r = mid - 1; } } printf("%lld\n", ans ); return 0; }
In the Kingdom of AtCoder, only banknotes are used as currency. There are 10100+110100+1 kinds of banknotes, with the values of 1,10,102,103,…,10(10100)1,10,102,103,…,10(10100). You have come shopping at a mall and are now buying a takoyaki machine with a value of NN. (Takoyaki is the name of a Japanese snack.)
To make the payment, you will choose some amount of money which is at least NN and give it to the clerk. Then, the clerk gives you back the change, which is the amount of money you give minus NN.
What will be the minimum possible number of total banknotes used by you and the clerk, when both choose the combination of banknotes to minimize this count?
Assume that you have sufficient numbers of banknotes, and so does the clerk.
在一个国家纸币只有$10^{100}+1$种面额,分别是$1, 10, 10^2, 10^3, \dots, 10^{(10^{100})}$
你须要去支付n元,多是你付出了一个更大的钱数,对方再找回你差值的钱。
问整个交易过程最少须要用到多少个纸币?
咱们从低位到高位看,第i位x,是选择方法1:付x个$10^i$元的纸币
仍是选择方法2:付一个$10^{i+1}$元的纸币在让对方找$10-x$个$10^i$ 纸币呢?
咱们能够看出对于每一位i,只有2个选择状况,即上述2种。
那么咱们不妨定义动态规划的状态$dp[i][0]$表明从低数第i位选择了方法1,$dp[i][1]$表明从低数第i位选择了方法2.
定义初始状态:
dp[n][0] = (s[n] - '0'); dp[n][1] = 10 - (s[n] - '0');
转移方程:
dp[i][0] = min(dp[i + 1][0] + (s[i] - '0'), dp[i + 1][1] + (s[i] - '0') + 1); dp[i][1] = min(dp[i + 1][0] + 10 - (s[i] - '0'), dp[i + 1][1] + 10 - (s[i] - '0' + 1));
char s[maxn]; ll dp[maxn][2]; int main() { //freopen("D:\\code\\text\\input.txt","r",stdin); //freopen("D:\\code\\text\\output.txt","w",stdout); s[0] = '0'; scanf("%s", s + 1); int n = strlen(s + 1); dp[n][0] = (s[n] - '0'); dp[n][1] = 10 - (s[n] - '0'); for (int i = n - 1; i >= 0; --i) { dp[i][0] = min(dp[i + 1][0] + (s[i] - '0'), dp[i + 1][1] + (s[i] - '0') + 1); dp[i][1] = min(dp[i + 1][0] + 10 - (s[i] - '0'), dp[i + 1][1] + 10 - (s[i] - '0' + 1)); } printf("%lld\n", min(dp[0][0], dp[0][1])); return 0; }