题目链接 题目大意: 有三个长度为n的字符串a、b、c,字符串都是小写字符; 有一个长度为n的模版t,模版会与字符串a、b、c匹配,匹配规则如下: 1、假如模版的字符为小写字母,则对应位置必须是相同字符才算匹配; 2、假如模版的字符为大写字母,则对应位置则不能是相同字符才算匹配; 比如说模板abc和字符串abc是匹配的,模板ABC和字符串def也是匹配的,模板ABC和字符串abc是不匹配的;
现在已知字符串a、b、c,问是否能够构造一个模板t,要求字符串a和b是匹配的,字符串c是不匹配的。
输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤1000) 每个样例4行 第一行,整数𝑛(1≤𝑛≤20),字符串长度 第2、3、4行,分别是字符串a、b、c;
输出: 每个样例第一行,有解则输出YES,无解则输出NO;
Examples input 4 1 a b c 2 aa bb aa 10 mathforces luckforces adhoccoder 3 acc abd abc
output YES NO YES NO
样例解释: 样例1,直接用模板C 样例3,可以用模板CODEforces
题目解析: 题目的意思比较绕,但是匹配规则还是比较清晰的,可以先简化题目。
先考虑字符串a和b,对于某个位置的字符: 如果a和b相同(假设都是字符x),那么模版可以字符x,也可以是字符X以外的大写字符; 如果a和b相同(假设是字符x和字符y),那么模版必须是字符X、Y以外的大写字符;
我们发现,不管字符串a和b的取值,总是可以找到满足要求的模版;
那么再考虑字符串c,要使得模版至少有一个配置是不匹配的,也就是至少有一个位置,字符串c该位置的字符与前面的都不同。
typedef long long lld;
class Solution {
static const int N = 201010;
int a[N];
public:
void solve() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
string a, b, c;
cin >> a >> b >> c;
int ans = 0;
for (int i = 0; i < n; ++i) if (a[i] != c[i] && b[i] != c[i]) ans = 1;
cout << (ans > 0 ? "YES" : "NO") << endl;
}
}
}
ac;
题目链接 题目大意: 有n个棍子,长度分别为2^𝑎𝑖; 从这些棍子里面挑出3个,组成一个三角形; 想知道,一共有多少种选择。 (三个棍子,顺序不同算一个组合,比如说1、2、3 和 3、2、1)
输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤10000) 每个样例2行 第一行 整数𝑛,表示n个棍子(1≤𝑛≤20) 第二行 n个整数,𝑎1,𝑎2,…,𝑎𝑛 (0≤𝑎𝑖≤𝑛 ).
输出: 每个样例第一行,输出能够组合成三角形的数量。
Examples input 4 7 1 1 1 1 1 1 1 4 3 2 1 3 3 1 2 3 1 1
output 35 2 0 0
题目解析: 先分析题目的数据特点。 由题目知道,三个不同的数字是无法组合成三角; 那么,有且仅有两种可能: 1、三个数字相同;(这种情况就是组合数,C(x, 3) 从x个相同数组中选择3个) 2、两个数字相同,剩下一个更小的数字;
将整数排序,从小到大。情况2的数量,就可以选定当前数字的2个棍子,再乘以前面的所有数字的数量。
typedef long long lld;
class Solution {
static const int N = 301010;
int a[N];
public:
void solve() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
map<int, int> h;
for (int i = 0; i < n; ++i) {
cin >> a[i];
h[a[i]]++;
}
lld ans = 0, sub = 0;
for (map<int, int>::iterator it = h.begin(); it != h.end(); ++it) {
int cnt = it->second;
if (cnt >= 3) {
ans += 1LL * cnt * (cnt - 1) * (cnt - 2) / 6;
}
if (cnt >= 2) {
ans += 1LL * cnt * (cnt - 1) / 2 * sub;
}
sub += cnt;
}
cout << ans << endl;
}
}
}
ac;
题目链接 题目大意: 有一个整数数组a,数组每个元素的乘积是2023; 数组移除了k个整数,剩下长度为n的数组b;
现在已知数组长度n和数组b,问能否找到原来的数组a。
输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤100) 每个样例2行 第一行,整数𝑛和k (1≤𝑛,𝑘≤5) 第二行,n个整数𝑏1,𝑏2,…,𝑏𝑛(1≤𝑏𝑖≤2023)
输出: 每个样例第一行,无解输出NO,有解输出YES; 如果有解,则第二行再输出被移除的k个整数;
Examples input 7 2 2 5 2 3 1 7 17 7 4 2 1 289 1 1 3 1 7 17 17 1 1 289 1 1 2023 1 3 1
output 1 1 0 0 0 1 3 0
题目解析: 题目的要求比较明确,当我们给出整数数组b时,假设最终的数组b乘积为m; m能够被2023整数时,剩余的k个数组就可以是[2023/m, 1, 1, 1】这样的数组来组成。 如果m不能被整数,那么就无解了。
typedef long long lld;
class Solution {
static const int N = 201010;
int a[N];
public:
void solve() {
int t;
cin >> t;
while (t--) {
int n, k;
cin >> n >> k;
int ans = 2023, ok = 1;
for (int i = 0; i < n; ++i) {
int x;
cin >> x;
if (ans % x == 0) ans /= x;
else ok = 0;
}
if (ok) {
cout << "YES\n" << ans;
while (k > 1) {
k--;
cout << " " << 1;
}
cout << endl;
}
else {
cout << "NO" << endl;
}
}
}
}
ac;
题目链接 题目大意: 给出两个整数a和b,现在要找到整数x,满足条件: 1、1≤𝑎<𝑏<𝑥,且1≤𝑥≤1e9; 2、a和b是x的因数,且是因数(x不算)中最大的两个;
比如说12 的因数有 [1,2,3,4,6],那么a和b就是4和6;
输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤10000) 每个样例一行,整数𝑎 , 𝑏 (1≤𝑎<𝑏≤1e9)
输出: 每个样例一行,输出满足要求的x;(题目保证有解)
Examples input 8 2 3 1 2 3 11 1 5 5 10 4 6 3 9 250000000 500000000
output 6 4 33 25 20 12 27 1000000000
题目解析: 先从小样例开始分析,容易知道当a=1的时候,答案是b^2; 当a=2的时候 [2, 3]=6 [2, 4]=8 [2, 5]=10 [2, 6]无解;(12的时候,3、4因子更大)
当a=3的时候 [3, 4]=12 [3, 5]=15 [3, 6]无解;(12的时候,因子4更大)
当a=4的时候 [4, 5]=20 [4, 6]=12 [4, 7]=28 [4, 8]=16 [4, 9]无解;(36的时候,因子3x12=36,12更大)
我们发现,有解/无解的时候,与a、b的因子有一个强关联,
比如说[2, 6]无解,实际上6=2x3,那不管乘以任何数字k,都容易产生2 * k、3 * k这样的因子,一定比2要大; [4, 9]无解,也是同理4=2x2, 9=3x3,理论上的有4、9因子的最小值就是2x2x3x3=36,但是会产生很多较大因子。
比如说有解的时候,大多数值都是最小公倍数。 但是有例外是[2, 4]和[4, 8],当他们b整除a的时候,最小公倍数是b,但是题目要求是x>b,所以x要乘以一个值k。 下面说明k的取值关系。
假设k=b/a,那么b=k * a, b * (b/a)=b * k=(a * k) * k 假如是b * 2的话,b * 2=a * k * 2,那么因子里面就会多出来一个2 * a,此时如果一旦b/a != 2,那么必会有一个2 * a的因子 大于原来的因子a; 假如是b * (b/a)的话,只会产生一个k * k的因子,a * k是等于b的,并且我们可以知道有解的条件是k * k<a
这样题目的大体思路就有了。 注意:最小公倍数的求法,可以用最大公约数来算。(我自己忘了,竟然尝试用因数分解去做,结果超时了)
typedef long long lld;
class Solution {
static const int N = 201010;
long gcd(lld a, lld b){
if (b==0) return a;
return gcd(b, a%b);
}
public:
void solve() {
int t;
cin >> t;
while (t--) {
int a, b;
cin >> a >> b;
int n = a, m = b;
if (m % n == 0) {
// 表示b是a的倍数,此时只需要将m*(m / n)就行
// 假设k=m/n,那么m=k*n, m*(m/n)=m*k=(n*k)*k
// 假如是m*2的话,m*2=n*k*2,那么因子里面就会多出来一个2*n,此时如果一旦m/n != 2,那么必然会有一个2*n的因子 大于原来的因子n;
// 假如是m * (m/n)的话,只会产生一个k*k的因子,n*k是等于m的,并且我们可以知道有解的条件是k*k<n
cout << m * (m / n) << endl;
}
else {
lld ans = a * 1LL * b / gcd(a, b);
cout << ans << endl;
}
}
}
ac;
题目链接 题目大意: 有n个整数的数组a,现在有Alice和Bob两个人玩游戏,Alice先手。 游戏规则如下: 1、数组中只有一个元素时结束游戏,当前数字为最终结果; 2、每次可以选择数组2个整数,移除对应整数;然后将整数相加再除以2,向下取整,再乘以2,最终将数字重新加回去数组;(比如说[1,3]=4, [2,3]=4)
Alice的目标是让结果尽可能大,Bob的目标是让结果尽可能小。 现在想知道,当只有数组前k个数字参与游戏时(𝑘=1,2,…,𝑛),最终的游戏结果是什么。
输入: 第一行,整数𝑡 表示t个样例 𝑡 (1≤𝑡≤10000) 每个样例2行 第一行,整数𝑛(1≤𝑛≤1e5) 第二行,n个整数𝑎1,𝑎2,…,𝑎𝑛 (1≤𝑎𝑖≤1e9)
输出: 每个样例一行,共n个整数;第k个数字,表示只有前k个数字参与游戏时,最终的结果。
Examples input 4 1 31 6 6 3 7 2 5 4 3 3 10 11 5 7 13 11 19 1
output 31 6 8 16 18 22 26 3 12 24 7 20 30 48 50
题目解析: 先不考虑k的取值情况,只看整个数组都参与游戏。 数组中的数字,我们可以分为奇数和偶数,已知偶数+偶数、奇数+奇数的操作只会合并数字,不会有任何变化。只有奇偶数相加,此时最终结果会-1。 这样, 我们假设有x个奇数; 先手每次优先消耗2个奇数,产出1个偶数; 后手每次优先消耗1个奇数+1个偶数,产出1个偶数;(偶数必然存在,因为先手会产出偶数) 这样我们就可以得到一个策略: n=1,ans=sum(用sum来表示前n项和) n=2,ans=sum n=3=2+1,ans=sum-1 n=4=2+1 +1, ans=sum-2 n=5=2+1 +2, ans=sum-1 n=6=2+1 + 2+1, ans=sum-2 n=7=2+1 + 2+1 +1, ans=sum-3 ... 依次类推,我们知道3个奇数是一个循环,最终ans= sum - (n + 2) / 3 + ((n + 1) % 3 == 0)
typedef long long lld;
class Solution {
static const int N = 201010;
int a[N];
public:
void solve() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<lld> ans;
lld sum = 0, cnt = 0;;
for (int i = 0; i < n; ++i) {
int k;
cin >> k;
sum += k;
if (k % 2) ++cnt;
if (i == 0) ans.push_back(sum);
else {
ans.push_back(sum - (cnt + 2) / 3 + ((cnt + 1) % 3 == 0));
}
}
for (int i = 0; i < n; ++i) {
cout << ans[i] << " ";
}
cout << endl;
}
}
}
ac;