纪念第一次补全cf:
感动~~
A. Plus One on the Subset
题目大意:给出一个数组,每次我们可以选几个数+1,问至少多少次使得该数组中所有数大小相等。
签到
输出最大值 - 最小值即可, 因为对于每个数每次我们都只能使其增加1.
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main(void)
{
int T;
scanf("%d", &T);
while(T --)
{
int n;
scanf("%d", &n);
vector<int> vec(n);
int maxn = 0, minn = 1e9 + 1;
for(int i = 0; i < n; i ++)
{
scanf("%d", &vec[i]);
if(vec[i] > maxn) maxn = vec[i];
if(vec[i] < minn) minn = vec[i];
}
printf("%d\n", maxn - minn);
}
return 0;
}
B. Make AP
题目大意:
给出三个数a, b, c, 可以进行一次操作使得其中一个数 * m, 能否找到这样的一个m,使得a, b, c为等差数列。
等差公式
分析:
等差公式: a + c = 2 * b
分类讨论扩大a, c或者b即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int arr[20];
int main(void)
{
int T;
scanf("%d", &T);
while(T --)
{
int a, b, c;
cin >> a >> b >> c;
bool flag = false;
int temp = (2 * b) - c;
if((a + c) % (2 * b) == 0) flag = true;
if(temp > 0 && temp % a == 0) flag = true;
temp = (2 * b) - a;
if(temp > 0 && temp % c == 0) flag = true;
if(flag) puts("YES");
else puts("NO");
}
return 0;
}
C. Division by Two and Permutation
题目大意:
给出n个数,可以使其中的数除以2(向下取整),可以进行无数次该操作。问能否得到一个1-n的全排列。
贪心
分析
- 若当前值 > n, 让其不断除以2, 找到第一个未标记的1-n的值,标记上。
若无解,最后该值不断除以2会得0, 切忌死循环 (悲痛wa)
- 切记找未标记的下一个值。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main(void)
{
int T;
scanf("%d", &T);
while(T --)
{
int n;
scanf("%d", &n);
map<int, int> mp;
int maxn = 0;
for(int i = 0; i < n; i ++)
{
int x;
scanf("%d", &x);
while(x > n){
x /= 2;
}
while(mp[x] && x) x /= 2;
mp[x] ++;
}
bool flag = true;
for(int i = 1; i <= n; i ++)
{
if(mp[i] == 0) {
flag = false;
break;
}
}
if(flag) puts("YES");
else puts("NO");
}
return 0;
}
D. Palindromes Coloring
题目大意:给出一个字符串和k种颜色,要求每种颜色至少要有一个字母填涂,涂色完毕后,填涂同一种颜色的字符可以重新排列,从而组成一个新的字符串(要求必须是一个回文串),问,得到的k个回文字符串长度最小的那个长度最大是多少?
思维、贪心
分析
-
回文串性质:
(1)一个回文串是偶数是,每个字母出现的次数均为偶数。如aabbcc, acbbca
(2)如果是奇数,有一个字母出现了的次数为奇数,位于中间 : acbbbca -
每个字母按照对数分配给每个字符串,这样组成的字符串是偶数的,可以构成回文串; 再看看剩下的未分配的字母(本来为奇数的字母 + 未分配给字符串的成对的字母), 若有>=k个,则可以给每一个字符串一个(放到中间, 如acbca)。
比赛的时候想到了分奇偶,但没想到成对分配。还是要考虑回文串的性质的
【以后遇到该种类型的题,先思考隐藏的性质比较好】
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main(void)
{
int T;
scanf("%d", &T);
while(T --)
{
int n, k;
scanf("%d%d", &n, &k);
string s;
cin >> s;
int st[30];
memset(st, 0, sizeof st);
int cnt = 0;
for(int i = 0; i < s.size(); i ++)
{
st[s[i] - 'a'] ++;
}
int ans = 0, t = 0;
for(int i = 0; i < 26; i ++)
{
if(st[i] % 2) t ++;
ans += st[i] / 2; //多少对
}
t += 2 * (ans % k);
ans /= k;
if(t >= k) ans = ans * 2 + 1;
else ans *= 2;
cout << ans << endl;
}
return 0;
}
E. Masha-forgetful
题目大意:
给出n个字符串,和另一个字符串s。问s能否用前n个字符串的子串表示出来(要求字串长度>=2).。可以的话按照指定格式输出,不可以输出-1。
分析
-
前n个字符串分成2个字符和三个字符起来,然后分析s能否由这些小段组成
(1)合理性:若s中长度为奇数的子串是某个字符串的子串, 可以将该奇数分成2 * a + 3 * b
,即a个两个字母的小子串 + b个三个字母的小子串; 若长度为偶数,可以分成a 个两个字母的子串。
(2)最优性:s中长度越小的子串 是 前n个串的子串的概率越大。 -
存储我们用vector, 存完之后如何判断能否拼成s?
我们这里运用了dp
的思想。
(1)状态表示:dp[i]表示 i 前面这段的起点信息, 当dp[i]!= -1时, s 中 i 之前的字符都是可以得到的。
(2)状态转移:则当dp[i + 1 - 2]存在且合法时(即前i - 1个字符都能懂n个字符串中得到),前n个字符串能组成s[i-1] - s[i]时,我们状态可以由其转移过来。也就是说i + 1之前的这小段是可以得到的起点是 i - 1。dp[i + 1] = i - 1;
dp[i-3]同理。
此时处理dp[i]存储的是以i - 1结尾的这段小段在前n个字符串中的信息:l,r以及在第几个字符串中。
(3)若dp[m] != -1, 则m之前的都可以得到,s是可以得到的。 -
输出答案时,我们需要
从后往前推
,dp[m]固定,推出前面小段的信息,存储在答案数组中,因此,输出答案时,需要翻转一下,从前往后输出。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
void solve()
{
int n, m, i, j;
vector<int> num_2[10][10];
vector<int> num_3[10][10][10];
cin >> n >> m;
string s;
for(int i = 0; i < n; i ++)
{
cin >> s;
for(int j = 0; j < m - 1; j ++)
{
num_2[s[j] - '0'][s[j + 1] - '0'] = {j + 1, j + 2, i + 1};
}
for(int j = 0; j + 2 < m; j ++)
{
num_3[s[j]-'0'][s[j + 1] - '0'][s[j+2]-'0'] = {j + 1, j + 3, i + 1};
}
}
cin >> s;
vector<int> dp(m+1, -1);
dp[0] = 0;
for(int i = 1; i < m; i ++)
{
if(num_2[s[i - 1] - '0'][s[i] - '0'].size() && dp[i + 1 - 2] != -1)
{
dp[i + 1] = i - 1;
}
if(i >= 2)
{
if(num_3[s[i - 2]-'0'][s[i - 1] - '0'][s[i] - '0'].size() && dp[i+1-3] != -1){
dp[i + 1] = i - 2;
}
}
}
if(dp[m] == -1)
{
puts("-1");
return ;
}
i = m;
vector<vector<int>>ans;
while(i > 0)
{
if(dp[i] == i - 3)
{
ans.push_back(num_3[s[i - 1 - 2] - '0'][s[i - 1 - 1] - '0'][s[i - 1]-'0']);
i -= 3;
}
else{
ans.push_back(num_2[s[i - 1 - 1]-'0'][s[i - 1] - '0']);
i -= 2;
}
}
reverse(ans.begin(), ans.end());
cout << ans.size() << endl;
for(auto &it: ans)
{
cout << it[0] << " " << it[1] << " " << it[2] <<endl;
}
}
int main(void)
{
int T;
scanf("%d", &T);
while(T --)
{
solve();
}
return 0;
}
F. Interacdive Problem
题目大意:给出一个x (1 <= x < n)和 n, 你可以询问 + c, 代表 x = x + c, 会返回给 x / n(下取整)。
你可以询问至多10次,输出当前这个x是多少。
二分、思维、交互题
分析
-
当x < n时, x / n 是0;
当 x >= n 且 x < 2n时,返回的是1;
当 x >= 2n 且 x < 3n时,返回的时2
因此具有单调性。可以用二分. -
对于中间值mid, 当前期望加的值为 n - mid % n, 这样得到的期望值答案是:mid / n + 1。 当满足这个条件时,x位于[mid, r]。 不满足时,x位于[l, mid - 1]。我们每次询问都会给x加上一个值,l,r相应的加上该值即可。n不变。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main(void)
{
int n;
cin >> n;
int l = 1, r = n - 1;
while(l < r)
{
int mid = l + r + 1>> 1;
int x = n - mid % n;
int y = mid / n + 1;
cout << "+ " << x << endl;
int ans;
cin >> ans;
if(ans == y) l = mid;
else r = mid - 1;
l += x, r += x;
}
cout << "! " << l << endl;
return 0;
}
G. MinOr Tree
题目大意:
给出一个n个点m条边的图,要求剩下n-1条边,使得该图连通,并且各个边的按位或得到的值尽可能小,求该最小值。(最小或树)
贪心、位 优化
思路:
- 答案不会超过2 ^ 30次方, 二进制从高位枚举,若该位取0,仍能构成连通图则取0, 如不能则取1.得到的答案我们记为res。
当时看到这种解法是,我在想,能否满足他是n-1条边的限制。试想,若能去掉一些边使得res更小,在按位枚举时就会去掉,因此剩下的边一定能够去掉一些无关res大小的边,并且使得剩下的n-1为一个连通子图。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 200005;
int n, m, res;
struct node{
int a, b, w;
}e[N];
int p[N];
int find(int x)
{
return x != p[x] ? p[x] = find(p[x]) : x;
}
bool check(int k)
{
for(int x = 1; x <= n; x ++) p[x] = x;
for(int i = 0; i < m; i ++)
{
if(((e[i].w | res) >> k) == (res >> k)){
p[find(e[i].a)] = find(e[i].b);
}
}
int cnt = 0;
for(int x = 1; x <= n; x ++)
{
if(x == p[x])
{
cnt ++;
}
}
return cnt > 1;
}
int main(void)
{
int T;
scanf("%d", &T);
while(T --)
{
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i ++)
{
scanf("%d%d%d", &e[i].a, &e[i].b, &e[i].w);
}
res = 0;
for(int k = 29; k != -1; k --)
{
if(check(k)) res |= (1 << k);
}
printf("%d\n", res);
}
return 0;
}
这次cf又掉分了,嘤嘤嘤。纵使虐我千百次,我仍待它如初恋。下次可上点分吧…