程序员进阶之算法练习(一百)

新年伊始,终到百篇,龙年大吉。

题目1

题目链接
题目大意:
给出一个整数,问该整数能否切分为两个数字a和b,满足:
1、a和b都不包括前导零,是一个正常的数字;
2、a和b都大于0;
3、b > a;

如果可以,则输出数字a和b;如果不可以则输出-1;

输入:
第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤10000)
每个样例一行,单个整数 (数字长度为2~8)

输出:
每个样例一行,如果可以,则输出数字a和b;如果不可以则输出-1;

Examples
input
5
20002001
391125
200200
2001000
12

output
2000 2001
39 1125
-1
200 1000
1 2

题目解析:
按照题目的要求,a要尽可能小,b要尽可能大。
由于题目给出的数字本身就合法,那么将第一个数字开始分为a,往后找到第一个非零的数字就分给b,这样b一定是最大的。
从字符串上切分好a和b,接下来就是转成数字。
这里为了便于计算,从字符串a右边开始往左边枚举每一个位置上的数字,就可以得到数字a。(数字b同理,也可以字符串切割后,用sscanf取巧)

class Solution {
    static const int N = 201010;
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            string str;
            cin >> str;
            int k = 1, n = str.length();
            while (k < n) {
                if (str[k] != '0') break;
                ++k;
            }
            if (k >= n) {
                cout << -1 << endl;
                continue;;
            }
            int x = 0, y = 0;
            int tmp = k - 1, val = 1;
            while (tmp >= 0) {
                x += val * (str[tmp] - '0');
                --tmp;
                val *= 10;
            }
            tmp = n - 1, val = 1;
            while (tmp >= k) {
                y += val * (str[tmp] - '0');
                --tmp;
                val *= 10;
            }
            if (x < y) cout << x << " " << y << endl;
            else  cout << -1 << endl;
        }
    }
}
ac;

题目2

题目链接
题目大意:
给出一个01字符组成的字符串𝑠,现在可以对字符串进行任意次下面操作:
1、删除字符串中的某个一个字符,代价为1;
2、调换两个位置上的字符,代价为0;

现在要求,若干次操作后的字符串t,t上面每一个字符都与原来字符串s的字符相反,比如说:
s=011
那么t=10,最小操作代价是1,移除一个字符1,然后交换一次0、1的位置;

s=111100
那么t=00,最小操作代价是4,移除所有字符1;

问生成满足要求的字符串t,最小的代价是多少。(注意移除所有字符也满足要求)

输入:
第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤10000)
每个样例一行,字符串𝑠 (1≤ |𝑠| ≤2⋅1e5)

输出:
每个样例一行,输出满足题目要求的最小代价;

Examples
input
4
0
011
0101110001
111100

output
1
1
0
4

题目解析:
按照题目的要求,直接看最终字符串t的样式,比如说s=111100,那么t=001111;
那么只需要累计原来0、1的数字数量,然后从左到右枚举t的位置,直到剩下的字符无法填充,那么就得到t的最大长度;
得到t的最大长度k,那么需要移除的字符串长度就是n--k。

class Solution {
    static const int N = 201010;
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            string str;
            cin >> str;
            int n = str.length(), x = 0, y = 0;
            for (int i = 0; i < n; ++i)
                if (str[i] == '0') ++x;
                else ++y;
            int k = 0, cntX = x, cntY = y;
            while (k < n) {
                if (str[k] == '0') {
                    if (y > 0) --y;
                    else break;
                }
                else {
                    if (x > 0) --x;
                    else break;
                }
                ++k;
            }
            if (x + y == 0) {
                cout << 0 << endl;
            }
            else {
                cout << n - k << endl;
            }
        }
    }
}
ac;

题目3

题目链接
题目大意:
给出一个空的数组,现在有两个操作:
操作1,往数组添加一个数字2^x;
操作2,询问数组中的若干个数字,数字和是否可以为w;

输入:
第一行,整数𝑡 表示m个操作 (1≤m≤100000)
每个操作一行
操作1,是输入1和x (0≤x≤29 ).
操作2,是输入2和w;(0≤w≤1e9 ).

输出:
每个操作2输出一行,存在则输出YES,不存在输出NO;

Examples
input
5
1 0
1 0
1 0
2 3
2 4

output
YES
NO

题目解析:
题目的数据范围简化了题目,首先x比较小,数组中最多只有30个整数类型,那么可以按照这个规则聚类;
其次,在判断数组是否存在某个元素和时,可以从大到小遍历数组,对于某个元素y如果小于等于当前w,则优先取用,并且w=w-y,直到数组末尾;如果此时w=0,则有解,否则无解;

class Solution {
   static const int M = 536870912; // 2^29
   int a[30];
public:
   void solve() {
       int t;
       cin >> t;
       while (t--) {
           int k, x;
           cin >> k >> x;
           if (k == 1) a[x]++;
           else {
               int cur = M;
               for (int i = 29; i >= 0; --i) {
                   if (a[i] > 0 && x >= cur) {
                       int left = 1, right = a[i] + 1;
                       int find = left;
                       while (left < right) {
                           int mid = (left + right) / 2;
                           lld sum = 1LL * mid * cur;
                           if (sum > x) {
                               right = mid;
                           }
                           else {
                               find = mid;
                               left = mid + 1;
                           }
                       }
                       x -= find * cur;
                   }
                   cur /= 2;
               }
               cout << (x == 0 ? "YES" : "NO") << endl;
           }
           
       }
   }
}
ac;

题目4

题目链接
题目大意:
有两个整数n和k,n表示字符串长度,k表示字符串由前k个小写字符;
现在需要构造一个字符串s,要求任何长度为n的字符串,都是字符串s的子序列;

输入:
第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤676)
每个样例一行,整数n和k (1≤𝑛≤26 ) and (1≤𝑘≤26 ).

输出:
每个样例一行,输出字符串s,如果有多个则输出最短长度的字符串;

Examples
input
4
1 2
2 1
2 2
2 3

output
ab
aa
baab
abcbac

题目解析:
题目的要求,所有常读为n的字符串,在拼接的时候就可以看成是n个选择,每次从k个字符中选择一个;
那么在构造的时候,可以采用这样的策略:
我们重复abc/abc/abc这样的字符串,每一组都相当有k个不同字符的桶。
这样构造出来的结果就能满足要求。

class Solution {
    static const int N = 201010;
public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n, k;
            cin >> n >> k;
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < k; ++j) putchar('a' + j);
            }
            cout << endl;
        }
    }
}
ac;

题目5

题目链接
题目大意:
有一个正整数x,现在需要把x分成n个正整数,这些正整数之和是x;
现在要求,n个正整数的最大公约数,尽可能的大;

输入:
第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤1000)
每个样例一行,整数𝑥和 𝑛 (1≤𝑥≤1e8) and (1≤𝑛≤𝑥).

输出:
每个样例一行,输出最大的公约数。

Examples
input
3
10 3
5 5
420 69

output
2
1
6

题目解析:
按照题目的要求,全部拆分成数字1,必然可以拆出满足要求:
k-1个整数1,剩下的整数是x-n-1,这些整数的最大公约数是1;

同理,假如最大公约数是2,可以这么拆:
k-1个整数2,剩下的整数是x-2n-2,最大的公约数是2;

也就是说,假设最大公约数是k,也可以这么安排:n-1个整数k,剩下是x-kn-k;

由于题目的范围不大,那么枚举最大公约数的数字就好。

class Solution {
  static const int N = 201010;
public:
  void solve() {
      int t;
      cin >> t;
      while (t--) {
          int x, n;
          cin >> x >> n;
          int k = sqrt(x) + 1;
          int ans = 1;
          for (int i = 1; i <= k; ++i) {
              if (x % i == 0) {
                  if (i >= n) ans = max(ans, x / i);
                  if (x / i >= n) ans = max(ans, i);
              }
          }
          cout << ans << endl;
      }
  }
}
ac;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容