D. Slavic’s Exam
思路
1、根据贪心思想,对于所需要匹配的字母
x
x
x,其位置在s的越前面越好。
2、由此,我们从左往右遍历
s
s
s,若当前字母能和
t
t
t中的字母匹配上,那么就立马匹配。
3、考虑若没有问号该怎么解决:用一个指针指向当前
t
t
t中所需要匹配的字母,若与
s
s
s中的字母匹配
,指针就指向
t
t
t的下一个位置。
4、考虑
?
?
?代表了什么,由于其可以变成任意一个字母,因此碰到
?
?
?可以立马匹配
t
t
t中的字母。
5、若要求连续,可以用带有通配符的kmp算法解决。
代码
// Problem: Slavic's Exam
// Contest: Codeforces
// URL: https://m3.codeforces.com/contest/1999/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >mi;//小根堆
priority_queue<LL> ma;//大根堆
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
vector<int>a(N , 0);
void init(int n){
for(int i = 0 ; i <= n ; i ++){
a[i] = 0;
}
}
void solve()
{
string s , t;
cin >> s >> t;
int idx = 0;
int mx = t.size();
int len = s.size();
for(int i = 0 ; i < len ; i ++){
if(s[i] == '?' || s[i] == t[idx]){
s[i] = t[idx];
idx++;
}
if(idx == mx){
break;
}
}
if(idx == mx){
cout << "YES\n";
for(int i = 0 ; i < len ; i ++){
if(s[i] == '?'){
cout << 'a';
}
else{
cout << s[i];
}
}
cout << endl;
}
else{
cout <<"NO\n";
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
E. Triple Operations
思路
设
x
=
3
x
x=3x
x=3x为操作1,
y
=
y
/
3
y=y/3
y=y/3为操作2
1、先将
[
L
,
R
]
[L,R]
[L,R]内的所有数替换成变成
0
0
0所需要的操作2个数.例如
[
1
,
2
,
3
,
4
,
5
]
[1,2,3,4,5]
[1,2,3,4,5]将变成
[
1
,
1
,
2
,
2
,
2
]
[1,1,2,2,2]
[1,1,2,2,2]
2、一次操作等效为:在变换后的数组
a
a
a中选两个数
i
,
j
i,j
i,j,
a
i
=
a
i
+
1
(
a
i
>
0
)
,
a
j
=
a
j
−
1
(
a
j
>
0
)
a_{i} = a_{i}+1(a_{i} > 0),a_{j}=a_{j}-1(a_{j}>0)
ai=ai+1(ai>0),aj=aj−1(aj>0)
3、题目中的要求就等效为数组和变成0
4、若存在一个
a
i
=
0
a_{i}=0
ai=0,那么一次操作就能够将数组和减一,否则数组和不变。
5、最终答案就是将某个
a
i
a_{i}
ai变成0所需要的操作数+整个数组的和,显然
a
0
a_{0}
a0变成0所需要的操作数最小,因此答案变成了
a
0
a_{0}
a0+数组和
6、由于
[
3
i
,
3
i
+
1
−
1
]
[3^{i} , 3^{i + 1}-1]
[3i,3i+1−1]所需要的操作2是一样的,因此我们可以打包来运算,总共这样的区间数很少,因此复杂度满足。
代码
// Problem: Triple Operations
// Contest: Codeforces
// URL: https://m3.codeforces.com/contest/1999/problem/E
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >mi;//小根堆
priority_queue<LL> ma;//大根堆
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
vector<int>a(N , 0);
void init(int n){
for(int i = 0 ; i <= n ; i ++){
a[i] = 0;
}
}
void solve()
{
int l , r;
cin >> l >> r;
int ans = 0;
int x = l;
while(x){
ans += 2;
x /= 3;
}
int pre = l + 1;
int op = 1;
int rx = 1;
while(pre <= r){
int rr = rx * 3 - 1;
if(rr >= pre){
ans += (min(rr , r) - pre + 1) * op;
pre = rr + 1;
}
op++;
rx *= 3;
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
F. Expected Median
思路
1、整个数组只存在
0
,
1
0,1
0,1
2、对答案有贡献的只有中位数为
1
1
1的情况
3、由于是子序列,且最终需要排序,所以选择的位置不重要,只需要管从所有的0中选若干个0跟所有的1中选若干个1即可
4、选择的0的个数最多为
k
/
2
k/2
k/2,最少为
0
0
0
5、枚举选择0的个数,分别求出可能的方案并相加
代码
// Problem: Expected Median
// Contest: Codeforces
// URL: https://m3.codeforces.com/contest/1999/problem/F
// Memory Limit: 256 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
#define int long long
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pair<int,int>pl;
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
vector<int>a(N , 0);
void init(int n){
for(int i = 0 ; i <= n ; i ++){
a[i] = 0;
}
}
struct comb{
vector<LL>f , g;//阶乘以及分母式子的逆元
comb(){}
comb(int n) : f(n) , g(n){
init(n);
}
LL qpow(LL a , LL b)//快速幂
{
LL sum=1;
while(b){
if(b&1){
sum=sum*a%mod;
}
a=a*a%mod;
b>>=1;
}
return sum;
}
void init(int n){
f[0] = g[0] = 1;
for(int i = 1;i < n; i ++){
f[i] = f[i - 1] * i % mod; //计算i的阶乘
}
g[n - 1] = qpow(f[n - 1] , mod - 2);
for(int i = n - 1 ; i >= 1 ; i --){
g[i - 1] = g[i] * i % mod;
}
}
LL get(int n,int m){ //得到C(n,m)的组合数答案
if(n < m)
return 0;
else
return f[n] * g[m] % mod * g[n-m] % mod;
}
};
void solve()
{
int n , k;
cin >> n >> k;
comb calc(n + 5);
int mi = 0 , mx = k / 2;
int cnt[2] = {0 , 0};
for(int i = 0 ; i < n ; i ++){
int x;
cin >> x;
cnt[x]++;
}
int ans = 0;
for(int i = 0 ; i <= mx ; i ++){
ans += calc.get(cnt[0] , i) * calc.get(cnt[1] , k - i);
ans %= mod;
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
G2. Ruler (hard version)
思路
1、若我们只能问
?
a
a
? \ a \ a
? a a的情况,那么很容易想到用二分来解决答案
2、二分需要10次操作,显然不行
3、现在我们可以问
?
a
b
? \ a \ b
? a b,因此有两个数可以由我们控制,可以想到用类似于三分的思想解决
4、令
a
=
l
+
(
r
−
l
)
/
3
,
b
=
a
+
(
r
−
l
)
/
3
a=l+(r-l)/3 , b=a+(r-l)/3
a=l+(r−l)/3,b=a+(r−l)/3,然后进行询问,若给出的回答是
a
∗
b
a*b
a∗b那么代表了
x
x
x一定在
b
b
b的右侧;若给出的答案是
(
a
+
1
)
∗
b
(a+1)*b
(a+1)∗b,那么
x
x
x一定在
[
a
,
b
)
[a,b)
[a,b)之间;否则
x
x
x一定在
a
a
a的左侧。
代码
// Problem: Ruler (easy version)
// Contest: Codeforces
// URL: https://m3.codeforces.com/contest/1999/problem/G1
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 1e09+7;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >mi;//小根堆
priority_queue<LL> ma;//大根堆
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
vector<int>a(N , 0);
void init(int n){
for(int i = 0 ; i <= n ; i ++){
a[i] = 0;
}
}
void ask(int x , int y){
cout << "? " << x << " " << y << endl;
}
void solve()
{
int l = 2 , r = 999;
while(l < r){
int midl = l + (r - l) / 3;
int midr = midl + (r - l) / 3;
ask(midl , midr);
int ans;
cin >> ans;
if(ans == midl * midr){
l = midr + 1;
}
else if(ans == (midl + 1) * (midr + 1)){
r = midl;
}
else{
l = midl + 1;
r = midr;
}
}
cout << "! " << l << endl;
}
int main()
{
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}