Educational Codeforces Round 161 (Rated for Div. 2) A-C 题题解
A题 Tricky Template Problem - A - Codeforces
题目概述:给你三个长度相等的字符串 a , b , c a , b,c a,b,c,并告诉你长度为 n n n。你需要找出一个模板,使字符串 a , b a,b a,b 能与该模板相符,而字符串 c c c 不能与其完全相符,相符条件如下:
1.当模板里的一个位置的字母 t i t_i ti 为小写时,待匹配的字符串相应位置 s i s_i si 必须与其相同。
2.当模板里的一个位置的字母 t i t_i ti 为大写时,待匹配的字符串相应位置 s i s_i si 无论大小写,必须与其不同。(例如,如果模板中有字母 “A”,则不能在字符串的相应位置使用字母 “a”)
存在就输出YES,不存在就输出NO
题目类型:构造,字符串
要点注意:
1.我们只需知道这个 模板 t t t 存不存在,而不需要把这个 t t t 求出来。
2.根据题意和观察样例我们可以发现。(写法一)
(1)只要存在一个下标 i i i ,使得 a i = = b i a_i == b_i ai==bi 但 a i ! = c i a_i != c_i ai!=ci 时,该模板就可以存在(模板在 t i t_i ti 处取小写的 a i a_i ai),
(2)只要存在一个下标 i i i ,使得 a i ! = b i ! = c i a_i != b_i != c_i ai!=bi!=ci 时,该模板就可以存在(模板在 t i t_i ti 处取大写的 c i c_i ci)
3.(写法二)
只要存在一个下标 i i i ,使得 a i ! = c i a_i != c_i ai!=ci 且 b i ! = c i b_i != c_i bi!=ci 时,该模板就可以存在(模板在 t i t_i ti 处取大写的 c i c_i ci)
//
// Created by Mrlaolu on 2024/1/17.
//
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 1010;
void solve()
{
写法一
int n;
cin >> n;
string a,b,c;
cin >> a >> b >> c;
int flag = 1;
for(int i = 0;i < n;++i)
{
if(a[i] == b[i] && a[i] != c[i] || a[i] != b[i] && a[i] != c[i] && b[i] != c[i])
{cout << "YES\n";flag = 0;break;}
}
if(flag){cout << "NO\n";}
/* 写法二
int n;
cin >> n;
string a,b,c;
cin >> a >> b >> c;
int flag = 1;
for(int i = 0;i < n;++i)
{
if(a[i] != c[i] && b[i] != c[i] )
{cout << "YES\n";flag = 0;break;}
}
if(flag){cout << "NO\n";}
*/
}
signed main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}
B题 Forming Triangles Problem - B - Codeforces
题目概述:给你n根木棍,注意!!!给你的每根木棍的数字是它的长度的 2 2 2 次方(如给你 3 3 3 则意味着这根木棍的长度为 8 8 8 ( 2 3 = 8 2^3 = 8 23=8) )。求出有多少个组合能使木棍能组成一个三角形。
题目类型:构造,前缀和
要点注意:
1.通过举例观察,我们可以发现:因为 2 i + 1 = 2 ∗ 2 i = 2 i + 2 i 2^{i+1} = 2 * 2 ^ i = 2 ^ i + 2 ^ i 2i+1=2∗2i=2i+2i ,而第三条边只能小于两条边之和。所以要形成一个三角形,只能选取两个相同大小的边和一个小于等于前两个的边( a = b = 2 i , c < = 2 i a=b=2^i,c<=2^i a=b=2i,c<=2i),故可因此写出代码。
//
// Created by Mrlaolu on 2024/1/17.
//
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 1010;
void solve()
{
int n;
int ans = 0;
cin >> n;
multiset<int>a; //运用multiset的count函数,能快速知道一个值的个数(当然也可以用map)
map<int,int>xiaoyu; //前缀和思想,快速找出比 2^i 小的数的个数
int min1 = INT_MAX;
int max1 = 0;
for(int i = 0;i < n;++i)
{
int temp;
cin >> temp;
a.insert(temp);
xiaoyu[temp]++;
max1 = max(temp,max1);
min1 = min(temp,min1);
}
for(int i = min1 + 1;i <= max1;++i)
{
xiaoyu[i] += xiaoyu[i-1];
}
for(int i = min1;i <= max1;++i)
{
if(!a.count(i)){continue;}
if(a.count(i) >= 3){ans += a.count(i) * (a.count(i) - 1) * (a.count(i) - 2) / 6;} //当三条边相同的时候,拿出来特判
if(a.count(i) >= 2){ans += a.count(i) * (a.count(i) - 1) * (xiaoyu[i] - a.count(i)) / 2;} //组合数公式
}
cout << ans << endl;
}
signed main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}
C题 Closest Cities Problem - C - Codeforces
题目概述:先给你一串长为 n n n 的数组,分别代表着 a 1 , a 2 . . . a n a_1,a_2...a_n a1,a2...an 到 a 1 a_1 a1 的长度,这些城市分布在一条直线上。当下面给你 m m m 个操作,要算出从 $x $ 到 y y y 所要的最少的钱。如果前往的城市的为当前所在城市最近的一个,则收一枚硬币,否则收相应距离的硬币。
题目类型:前缀和,贪心
要点注意:
1.因为是求出所需最少的钱,那肯定是一步步从 x x x 走到 y y y,看看每一步能不能遇到最近的城市,从而少花点钱(因为去往最近的只用一枚硬币)。
2.如果每一次操作都从 x x x 一点点算到 y y y 肯定是会TLE的(或许)。观察到从城市 1 1 1开始往后走钱是一点点叠加起来的(有递推式 b i = b i − 1 + 从 a i 到 a i − 1 的路费 ( 1 或者 a i − a i − 1 ) ,其中 b i 为从城市 1 到 i , 所需的路费 b_i = b_{i - 1} + 从a_i到a_{i-1}的路费(1 或者 a_i - a_{i - 1}),其中 b_i 为从城市1到i,所需的路费 bi=bi−1+从ai到ai−1的路费(1或者ai−ai−1),其中bi为从城市1到i,所需的路费)。我们可以推广出公式( 从 x 到 y 的路费 = b x − b y 从x到y的路费 = b_x - b_y 从x到y的路费=bx−by)(当 x < y x < y x<y 时)。
3.我们也可以依据上面这条写出( c i = c i + 1 + 从 a i + 1 到 a i 的路费 ( 1 或者 a i + 1 − a i ) ,其中 c i 为从城市 n 到 i , 所需的路费 c_i = c_{i + 1} + 从a_{i+1}到a_i的路费(1 或者 a_{i+1}-a_i),其中 c_i 为从城市n到i,所需的路费 ci=ci+1+从ai+1到ai的路费(1或者ai+1−ai),其中ci为从城市n到i,所需的路费),从而推广出( 从 x 到 y 的路费 = c x − c y 从x到y的路费 = c_x - c_y 从x到y的路费=cx−cy)(当 x > y x > y x>y 时)。
//
// Created by Mrlaolu on 2024/1/17.
//
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 1e5+2;
vector<int>a(N);
map<pair<int,int>,int>m;
vector<int>c(N);
void solve()
{
int n;
cin >> n;
for(int i = 1;i <= n;++i)
cin >> a[i];
vector<int>toR(n+1); //toR 即为要点中的 数组b
vector<int>toL(n+1); //toL 即为要点中的 数组c
vector<int>c(n+1); //用于存每个城市的最近城市,方便算toR和toL时调用
c[1] = 2;
c[n] = n - 1;
for(int i = 2;i < n;++i) //存每个城市的最近城市
{
c[i] = ((a[i] - a[i - 1]) < (a[i + 1] - a[i]) ? i - 1 : i + 1);
}
for(int i = 1;i < n;++i)
{
toR[i + 1] = toR[i] + (c[i] == i + 1 ? 1 : a[i+1] - a[i]);
}
for(int i = n;i > 1;--i)
{
toL[i - 1] = toL[i] + (c[i] == i - 1 ? 1 : a[i] - a[i - 1]);
}
int t;
cin >> t;
while(t--)
{
int q,w;
cin >> q >> w;
if(q > w)
{cout << toL[w] - toL[q] << endl;}
else
{cout << toR[w] - toR[q] << endl;}
}
}
signed main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}