Codeforces Round 964 (Div. 4)(D~G)

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=aj1(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+11]所需要的操作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+(rl)/3,b=a+(rl)/3,然后进行询问,若给出的回答是 a ∗ b a*b ab那么代表了 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值