牛客练习赛86

A 取因数

题目大意

在纸上写一个数字 n,双方每次选择 n 的一个因数,然后划掉 n 并在纸上写下 n 减去这个数字的差使之成为新的 n,最后写数字 0 的人输。Alice先手。

主要思路
  • 奇数的因数都是奇数,因此奇数一定会变成偶数
  • 偶数可以通过-1变成奇数
  • 那么如果先手是偶数,那么可以通过-1维持对手是奇数,自己一直是偶数,持续到自己为2时,对手为1,对手必输,先手必胜

结论:偶数先手必胜,奇数先手必输

AC代码
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <string>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
using namespace std;
 
#define int long long
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef pair<int, int> P;
 
const int N = 200010;
int n, a[N];
 
signed main(void)
{
    cin >> n;
    if(n % 2) puts("Bob");
    else puts("Alice");
    return 0;
}

B A + B

题目大意

中文题

主要思路

n最大是100,因为k只有2,所以分3种情况即可

  • k == 0,可以从1020往后枚举n个
  • k == 1,可以枚举a = 10, b = 1, c = 11, 每轮b++, c++
  • k == 2,枚举a = 1, b = 11, c = 12,每轮a++, b为两个a合并(比如a = 1,b变为11,a为2,b变为22),c = a + b,也就是a + aa == aa + a形式
AC代码
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <string>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
using namespace std;
 
#define int long long
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef pair<int, int> P;
 
const int N = 200010;
int n, a[N];
 
int f(int x)
{
    int t = x;
    int cnt = 0;
    while(x)
    {
        x /= 10;
        cnt++;
    }
    return t * (int)pow(10, cnt) + t;
}
 
signed main(void)
{
    int n, k;
    cin >> k >> n;
    if(k == 0)
    {
        int t = 1020;
        for(int i = 0; i < n; i++)
        {
            cout << t << endl;
            t++;
        }
    }
    else if(k == 1)
    {
        int a = 10, b = 1, c = 11;
        for(int i = 0; i < n; i++)
        {
            cout << a << b << c << endl;
            b++, c++;
        }
    }
    else
    {
        int a = 1, b = 11, c = 12;
        for(int i = 0; i < n; i++)
        {
            cout << a << b << c << endl;
            a++, b = f(a), c = a + b;
        }
    }
    return 0;
}

C 取钱

题目大意

中文题

主要思路

我们先预处理出用a[i]纸币能凑不超过a[i + 1]金额的金额最大值sum和纸币张数cnt。

读入每一个金额b,先二分出小于等于b的a[i]的最大值,然后获得纸币数量最大值为cnt[i - 1] + (b - sum[i - 1]) / a[i], 金额为sum[i - 1] + (b - sum[i - 1]) / a[i] + a[i]

核心思想:贪心,从小到大将每一个a[i]的数量最大化

AC代码
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <string>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
using namespace std;
 
#define int long long
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef pair<int, int> P;
 
const int N = 200010;
int n, a[N];
int cnt[N];
int sum[N];
 
signed main(void)
{
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    a[n + 1] = 1e18+1;
    for(int i = 1; i <= n; i++)
    {
        int t = (a[i + 1] - sum[i - 1] - 1) / a[i];//t为最大金额小于a[i + 1],会用到最多多少a[i]
        cnt[i] = cnt[i - 1] + t;//总纸币数量
        sum[i] = sum[i - 1] + a[i] * t;//总价
    }
     
    int T;
    cin >> T;
    while(T--)
    {
        int num;
        cin >> num;
        int l = 0, r = n + 1;
        while(l < r)//二分小于等于当前num的最大面额
        {
            int mid = l + r + 1 >> 1;
            if(a[mid] <= num) l = mid;
            else r = mid - 1;
        }
        cout << sum[l - 1] + (num - sum[l - 1]) / a[l] * a[l] << ' ' << cnt[l - 1] + (num - sum[l - 1]) / a[l] << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值