程序员进阶之算法练习(五十九)

正文

题目1

题目链接
题目大意:
有n个糖果,分给两个人A和B,要求:
两个人都有分配到糖果;
糖果不能拆分,必须全部分分完;
A的糖果数量比B的要多;

问,最终有多少种分配方案。

输入:
第一行,整数表示有t个样例数量 (1≤≤1000)
接下来每个样例一行,整数 (1≤≤2⋅1e9)

输出:
每个样例一行,输出存在分配方案,不存在则输出0;

Examples
input
6
7
1
2
3
2000000000
763243547
output
3
0
0
1
999999999
381621773

样例解释:
样例1:
7个糖果,有下面3个方案:
=6, =1;
=5, =2;
=4, =3.

题目解析:
分糖条件写的很清楚,两个整数a和b,要求a 对于数字n来说,如果n是偶数,那么有n/2-1种可能;
如果n是奇数,那么有n/2种可能;
利用计算机整除的特性,可以表述为(n-1)/2;


int main(int argc, const char * argv[]) {
    // insert code here...
    
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        cout << (n - 1) / 2 << endl;
    }   
    
    return 0;
}

题目2

题目链接
题目大意:
有三个正整数n,a,b,现在需要构造一个字符串s,长度为n,只包含小写字母,并且满足要求:
字符串s中,任何长度为a的子串要包含b个不同的字符。

输入:
第一行,整数表示有t个样例数量 (1≤≤2000)
接下来每个样例一行,四个整数 , and (1≤≤≤2000,1≤≤min(26,))

输出:
每个样例一行,输出满足要求的字符串;(题目保证答案一定存在)

Examples
input
4
7 5 3
6 1 1
6 6 1
5 2 2
output
tleelte
qwerty
vvvvvv
abcde

题目解析:
题目的要求是,长度为a的子串中,有b个不同的字符;
那么将b个字符构成的字符串不断重复,即可满足题目要求;
比如说题目样例 7 5 3
b=3,则用abc不断循环,得到abcabca
样例 5 2 2
b=2,则用ab不断循环,得到ababa

实现较为简单。


int main(int argc, const char * argv[]) {
    // insert code here...
    
    int t;
    cin >> t;
    while (t--) {
        int n, a, b;
        cin >> n >> a >> b;
        int k = 0;
        for (int i = 0; i < n; ++i) {
            putchar('a' + k);
            k = (k + 1) % b;
        }
        puts("");
    }   
    
    return 0;
}

题目3

题目链接
题目大意:
有n个整数a[i],现在需要从中选择两组数字,要求:
1、两组数字的数量一样,每个整数只能划分到一个组内;
2、第一组的数字各不相同,第二组的数字完全相同;
现在希望两组数字尽可能的多,问最多一组能有几个整数。

输入:
第一行,整数表示有t个样例数量 (1≤≤10000)
接下来每个样例两行,第一行整数 (1≤≤2⋅1e5)
第二行n个整数 1,2,…, (1≤≤),

输出:
每个样例一行,整数x,表示一组最多能够有x个整数。

Examples
input
4
7
4 2 4 1 4 3 4
5
2 1 5 4 3
1
1
4
1 1 1 3
⁣output
⁣3
⁣1
⁣0
⁣2

题目解析:
假如没有要求2,那么直接平分,x最大值就是n/2;
单独考虑不同数字的情况,直接算出数组中有k个不同的整数q,再算出数组中最多重复的整数w;
大多数情况下,min(q, w)就是答案了。
但是存在q和w会公用一个整数,比如说1.2.3,3,3这种情况,或者1.2.3.4.5.2.2情况。

当w<=q-1的时候,重复的数字比较少,所以答案就是w;
如果w>q-1的时候,重复的数字比较多,那么优先把重复的数字分配到第一组,答案就是min(w-1,q);

int a[N];
map hmap;

int main(int argc, const char * argv[]) {
    // insert code here...
    
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        hmap.clear();
        int maxCount = 0;
        for (int i = 0; i < n; ++i) {
            int k;
            cin >> k;
            ++hmap[k];
            maxCount = max(maxCount, hmap[k]);
        }
        
        if (hmap.size() <= maxCount - 1) {
            cout << hmap.size() << endl;
        }
        else {
            cout << min((int)hmap.size() - 1, maxCount) << endl;
        }
    }   
    
    return 0;
}

题目4

题目链接
题目大意:
长度为n的字符串,一共有三种字符,'B', 'R', '?';
'?'的字符需要填充为'B'或者'R';
现在小明不喜欢相连两个字符是一样的, 现在需要知道怎么填充使得最终相连两个字符相同的情况尽可能少?
比如说"BRRRBBR"就有3个相连的字符相同,"BB"出现一次,"RR"出现两次;

输入:
第一行,整数表示有t个样例数量 (1≤≤100)
接下来每个样例两行,第一行整数 (1≤≤100)
第二行长度为n的字符串s

输出:
每个样例一行,输出由'B'和'R'字符串构成的字符串。

Examples
input
5
7
?R???BR
7
???R???
1
?
1
B
10
?R??RB??B?

output
BRRBRBR
BRBRBRB
B
B
BRRBRBBRBR

题目解析:
方案1,动态规划,dp[i][2]表示前i个字符,第i个字符为B、R的最小重复次数;
初始化的时候,如果第1个字符是?则dp[1][0]=dp[1][1]=0;
第1个字符是B,则dp[1][0]=0,dp[1][1]=n;(n是极大值,表示dp[1][1]不可取)
第1个字符是R,则dp[1][1]=0,dp[1][0]=n;(n是极大值,表示dp[1][0]不可取)
状态转移的时候,dp[i]可以由dp[i-1]来进行计算;
如果a[i]==B,则dp[i][0] = min(dp[i-1][0]+1, dp[i-1][1]); dp[i][1]=n;
如果a[i]==R,则dp[i][1] = min(dp[i-1][1]+1, dp[i-1][0]); dp[i][1]=n;
这样看最终dp[n]的最小值即可。

方案2,找到第一个不为?的字符,从这个位置分别向左右开始填充,每次优先选择相邻字符不相同的方案;
??R??
RBRBR

方案3,通过数学直接计算;
从左到右,如果第i个字符串前面??没有确定字符,则这段?不会产生特殊字符;若??前面有确定字符k,则根据a[i]和a[k]以及(i-k)可以直接计算出来有多少个相同字符;(0或者1)

考虑到题目要输出结果,还是方案2比较简单。

思考:
如果是要连续3个字符串不一样呢?

class Solution {
    static const int N = 200010;
    string str;
    char ans[N];

public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            cin >> str;
            int pos = n;
            for (int i = 0; i < n; ++i) {
                if (str[i] != '?') {
                    pos = i;
                    break;
                }
            }
            ans[n] = '\0';
            if (pos == n) {
                for (int i = 0; i < n; ++i) {
                    ans[i] = i % 2 ? 'B' : 'R';
                }
            }
            else {
                ans[pos] = str[pos];
                for (int i = pos - 1; i >= 0; --i) {
                    if (str[i] == '?') {
                        ans[i] = 'B' + 'R' - ans[i + 1];
                    }
                    else {
                        ans[i] = str[i];
                    }
                }
                for (int i = pos + 1; i < n; ++i) {
                    if (str[i] == '?') {
                        ans[i] = 'B' + 'R' - ans[i - 1];
                    }
                    else {
                        ans[i] = str[i];
                    }
                }
            }
            printf("%s\n", ans);
        }
    }
}
ac;

题目5

题目链接
题目大意:
从n个整数的数组中,找到(i, j) 要求 l ≤ a[i]+a[j] ≤ r,问有多少(i, j)符合要求;

输入:
第一行是整数t,表示有t个样例 (1≤≤10000 ).
每个样例第一行是整数,, (1≤≤2⋅1e5, 1≤≤≤1e9)
第二行是n个整数1,2,…, (1≤≤109).

输出:
(,)的数量,要求是 (<) 并且 ≤+≤.

Examples
input
4
3 4 7
5 1 2
5 5 8
5 1 2 4 3
4 100 1000
1 1 1 1
5 9 13
2 5 5 1 1

output
yes
2
7
0
1

题目解析:
题目要求的是任意a[i]和a[j],那么数组的顺序没有意义,可以直接将数组进行排序;
如果不考虑复杂度,我们可以枚举pair(i, j)是否满足要求,这样复杂度是N*N;
由于排序完之后,数组是有序的,我们在枚举pair(i, j)的时候,可以采用下面的策略:
从小到大枚举i,假设已经先取了数字a[i]并且i 我们可以采用二分查找来,也可以使用快捷方法lower_bound。


class Solution {
    static const int N = 200010;
public:
    int a[N];

public:
    void solve() {
        int t;
        cin >> t;
        while (t--) {
            int n, l, r;
            cin >> n >> l >> r;
            for (int i = 0; i < n; ++i) {
                cin >> a[i];
            }
            sort(a, a + n);
            lld sum = 0;
            for (int i = 0; i + 1 < n; ++i) {
                int left = l - a[i];
                int right = r - a[i] + 1;
                // 从i+1开始,找到第一个大于等于left的数字作为起点x
                int x = lower_bound(a + i + 1, a + n, left) - a;
                if (x >= n) {
                    continue;;
                }
                // 新x开始,找到第一个大于right的数字作为终点y
                int y = lower_bound(a + x, a + n, right) - a;
                sum += y - x;
            }
            cout << sum << endl;
        }
    }
}
ac;

你可能感兴趣的:(程序员进阶之算法练习(五十九))