AtCoder Beginner Contest 155 - D - Pairs ,-E - Payment 題解

AtCoder Beginner Contest 155 - D - Pairs ,-E - Payment 題解

D - Pairs

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;
}

E - Payment

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;
}
相關文章
相關標籤/搜索