Educational Codeforces Round 113 (Rated for Div. 2)A~E

A. Balanced Substring

题意:给出一种仅包含ab字母的字符串,要求给出区间l,r,使得区间内的a,b字符数量相同,找不到输出-1 -1

分析:找到连续的ab或ba即可

代码:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>

#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'

using namespace std;

typedef long long ll; 
typedef pair<int, int> PII;

const int N = 3e5 + 10, mod = 1e9 + 7;

int n, m, t, k;

int s[N], dp[N], f[N];
char g[N];

string str;

vector<int> vec;

void solve()
{
	cin >> n >> str;
	for (int i = 1; i < n; i++)
	{
		if (str[i] != str[i-1])
		{
			printf("%d %d\n", i, i + 1);
			return;
		}
	} 
	puts("-1 -1");
}

int main()
{
    t = 1;
    cin >> t;
    while(t--) 
        solve();
    return 0;
}

B. Chess Tournament

题意:所有队员只有两种想法,1,不败一场。2,至少能胜一场,输入n,输入长度为n的仅包含1和2的字符串,问是否存在满足所有队员的情况,i对j,胜利为'+',失败为'-',平局为'=',i=j为'X',不存在输出NO,存在输出YES,并输出n*n的状态

分析:对于要求不败的同学,可以均为平局,对于要求胜利一场的同学,可以查询与他对战的所有队伍,如果当前未确定状态,可以定为i对j胜利,j对i失败,存在不符合条件的输出NO,都符合输出YES,输出答案即可

代码:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>

#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'

using namespace std;

typedef long long ll; 
typedef pair<int, int> PII;

const int N = 50 + 10, mod = 1e9 + 7;

int n, m, t, k;

int s[N], dp[N], f[N];
char g[N][N];

string str;

vector<int> vec;

void solve()
{
	cin >> n >> str;
	for (int i = 0; i < str.size(); i++)
		for (int j = 0; j < str.size(); j++)
			g[i][j] = ' ';
	for (int i = 0; i < str.size(); i++)
		for (int j = 0; j < str.size(); j++)
			if (i == j) g[i][j] = 'X';
			else if (str[i] == '1') g[i][j] = g[j][i] = '=';
	for (int i = 0; i < str.size(); i++)
	{
		if (str[i] == '1') continue;
		int flag = 1;
		for (int j = 0; j < str.size(); j++)
		{
			if (i == j) continue;
			if (g[i][j] == ' ')
			{
				flag = 0;
				g[i][j] = '+';
				g[j][i] = '-';
				break;
			}
		}
		if (flag)
		{
			puts("NO");
			return;
		}
	}
	puts("YES");
	for (int i = 0; i < str.size(); i++)
	{
		for (int j = 0; j < str.size(); j++)
		{
			if (g[i][j] == ' ') g[i][j] = '=';
			printf("%c", g[i][j]);
		}puts("");
	}
}

int main()
{
    t = 1;
    cin >> t;
    while(t--) 
        solve();
    return 0;
}

C. Jury Meeting

题意:每个人输出有一个要叙述的事件数,初始不确定每个人说话顺序,当轮到那个人时,如果此时没有要叙述的事件,那么跳过,否则叙述完成后,自己的事件数--,问有多少种发言顺序可以使得不存在一个人同时说两件事

分析:分析可得,将初始所有事件数排序后,如果最大值的个数大于1个,那么随便排都成立,答案就是n!,否则如果最大值个数为1,如果比次大值的值大于1,那么无论如何都不可能,答案就是0,否则要保证不管怎么排,都要有至少一个次大值排在最大值之后。每次枚举最大值的位置,算出当前不成立的情况,就是所有次大值都在左侧,统计cnt,最后用所有情况数一减就好了,就是n!-cnt

代码:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>

#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'

using namespace std;

typedef long long ll; 
typedef pair<int, int> PII;

const int N = 3e5 + 10, mod = 998244353;

int n, m, t, k;

int s[N], dp[N], f[N], in[N], inv[N];
char g[N];

string str;

vector<int> vec;

int ksm(int a, int b, int p)
{
	int res = 1;
	while (b)
	{
		if (b & 1) res = 1ll * res * a % p;
		a = 1ll * a * a % p;
		b >>= 1;
	}
	return res;
}

void init()
{
	in[0] = inv[0] = in[1] = inv[1] = 1;
	for (int i = 2; i < N; i++)
	{
		in[i] = 1ll * in[i-1] * i % mod;
		inv[i] = 1ll * inv[i-1] * ksm(i, mod - 2, mod) % mod;
	}
}

int C(int n, int m)
{
	return 1ll * in[n] * inv[n-m] % mod * inv[m] % mod;
}

void solve()
{
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> s[i];
	sort(s, s + n);
	if (s[n-1] == s[n-2])
	{
		printf("%d\n", in[n]);
		return;
	}
	if (s[n-1] - s[n-2] > 1)
	{
		printf("0\n");
		return;
	}
	int cnt = 0;
	for (int i = 0; i < n; i++)
		if (s[i] == s[n-2])
			cnt++;
	int ans = 0;
	for (int i = cnt; i < n; i++)
		ans = (1ll * ans + 1ll * C(i, cnt) * in[cnt] % mod * in[n-1-cnt] % mod) % mod;
	printf("%d\n", (in[n] % mod - ans + mod) % mod);
}

int main()
{
	init();
    t = 1;
    cin >> t;
    while(t--) 
        solve();
    return 0;
}

D. Expression Evaluation Error

题意:有n*m条街道,k个人,询问只能走街道的情况下,有多少个,两个人的最短距离大于他们的曼哈顿距离

分析:对于每两行街道中不同列的和每两列中不同行的都属于,这道题思路简单,代码麻烦,为简化代码,考虑统一计算,排除相同区间重复记过的数在一个区间内,对于行或列,重复的大小是当前相同区间内已经有的数量,行列分别计算

代码:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>

#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'

using namespace std;

typedef long long ll; 
typedef pair<int, int> PII;

const int N = 3e5 + 10, mod = 998244353;

int n, m, t, k;

int s[N], dp[N], f[N];
char g[N];

string str;

vector<int> vec;

map<int, int> ma;
map<PII, int> mb;

PII p[N];

void solve()
{
	cin >> n >> m >> k;
	for (int i = 1; i <= n; i++) cin >> s[i]; sort(s + 1, s + 1 + n);
	for (int i = 1; i <= m; i++) cin >> f[i]; sort(f + 1, f + 1 + m);
	for (int i = 1; i <= k; i++) cin >> p[i].x >> p[i].y;
	ll ans = 0;
	ma.clear(), mb.clear();
	for (int i = 1; i <= k; i++)
	{
		int a = lower_bound(s+1, s+1+n, p[i].x) - s;
		int b = lower_bound(f+1, f+1+m, p[i].y) - f;
		if (s[a] == p[i].x && f[b] != p[i].y)
		{
			ans += ma[b]++;
			ans -= mb[{a, b}]++;
		}
	}
	ma.clear(), mb.clear();
	for (int i = 1; i <= k; i++)
	{
		int a = lower_bound(s+1, s+1+n, p[i].x) - s;
		int b = lower_bound(f+1, f+1+m, p[i].y) - f;
		if (s[a] != p[i].x && f[b] == p[i].y)
		{
			ans += ma[a]++;
			ans -= mb[{a, b}]++;
		}
	}
	cout << ans << endl;
}

int main()
{
    t = 1;
    cin >> t;
    while(t--) 
        solve();
    return 0;
}

E. Non-Decreasing Dilemma

题意:两两淘汰制,第一为第一,第二为第二,第2i+1到第2i+1的排名为2i,计算h = (i=12kiApi)%998244353,pi为第i个人的排名,给定k,A,h,要求给出pi序列,若不存在输出-1,k<=5,A<=1e8,h余数范围内

分析:k的范围是5,对于所有情况枚举的话是225就是232是不够的,所以进一步看,发现如果不算左右两边的1和2的话,左右两边基本是基本相同的,所以考虑枚举224,然后对于每个值枚举1和2的位置,用map记录查询,就是224,代码实现较麻烦,预处理排名i对应的Ak然后不改变位置,第一部分都是1到2k1第二部分都是2k1+12k,只改变他们的排名顺序,前一部分用ma存放,后一部分用map存,只有可能是第一个部分有1,第二部分有2,或者第一部分有2,后一部分有1,两种情况都不存在的话,就不可能存在答案,遍利过程挺神奇,因为题目是两两淘汰制,所以所以对于前k回合的答案之后,第k+1回合会有k个排名分别对应在前k+1回合的所有人的前面或者后面,5轮回合都这么算,所以就要枚举1<<2k1种情况,然后用当前算出的h值域vector对应保存,对于两组map,在第一组的map中遍利,去第二组的map中查询对应的数值是否存在。如果1在左边,2在右边找不到就交换1和2的位置继续找,再找不到就是不存在,存在输出答案即可,否不存在输出-1

注:头文件numeric是函数iota(s, s + n, a)的头文件,该函数的作用是将区间的s变成以a为第一个数,d为1的等差数列

代码:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#include <numeric>

#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'

using namespace std;

typedef long long ll; 
typedef pair<int, int> PII;

const int N = 3e5 + 10, mod = 998244353;

int n, m, t, k;

map<int, vector<int> > G(vector<int> iv, vector<int> V, vector<int> raw)
{
    map<int, vector<int>>ret;
    for(int i=0; i<1<<((int)iv.size()-1); ++i)
    {
        int ni = i;
        vector<int> cur = {0};
        for(int j=1; j<(int)V.size(); ++j)
        {
            vector<int> n;
            for(int x: cur)
            {
                if(ni&1) n.push_back(x), n.push_back(j);
                else n.push_back(j), n.push_back(x);
                ni >>= 1;
            }
            cur = n;
        }
        int ans = 0;
        vector<int> r(iv.size());
        for(int i=0; i<(int)iv.size(); ++i)
            ans = (1LL*iv[i]*V[cur[i]]+ans)%mod, r[i] = raw[cur[i]];
        ret[ans] = r;
 
    }
    return ret;
}

void solve()
{
	int A, h;
	cin >> k >> A >> h;
	vector<int> V(k), Vr(k);
	V[0] = A, Vr[0] = 1;
	for (int i = 1; i < k; i++) V[i] = 1ll * V[i-1] * V[i-1] % mod, Vr[i] = 2 * Vr[i-1];
	for (int &x : Vr) ++x;
	for (int &x : V) x = 1ll * x * A % mod;
	vector<int> U = V, Ur = Vr; 
	U[0] = A; Ur[0] = 1;
	vector<int> X(1 << (k-1)), Y(1 << (k-1));
	iota(X.begin(), X.end(), 1);
	iota(Y.begin(), Y.end(), 1 + (1 << (k-1)));
	for (int i = 0; i < 2; i++)
	{
		auto M1 = G(X, U, Ur);
		auto M2 = G(Y, V, Vr);
		map<int, vector<int> >::reverse_iterator iter;
		for(iter = M1.rbegin(); iter != M1.rend(); iter++)
        {
        	int a = iter->first;
        	vector<int> b = iter->second;
            int targ = h-a; if (targ < 0) targ += mod;
            auto it = M2.find(targ);
            if(it != M2.end())
            {
                for(auto x: b) cout << x << " ";
                for(auto x: it->second) cout << x << " ";
                cout << endl;
                return;
            }
        }
        swap(U, V);
        swap(Ur, Vr);
	}
	cout << -1 << endl;
}

int main()
{
    t = 1;
//    cin >> t;
    while(t--) 
        solve();
    return 0;
}
posted @   forleaves  阅读(120)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示