Codeforces Round #829 (Div. 2)

A

核心思路:我们会发现如果就这么从左向右处理好像不太好处理的样子。因为最后几个Q我们不好去计算了,所以这里有一个很巧妙的点,那就是把那个字符串给逆序,然后我们从左往右统计A和Q,遇到A就是++,Q就--.如果小于0就一定不是了。

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int N = 1e5+10;//表示的是高精度位数
char s[N];
int vis[N];
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n;
		string s;
		cin >> s;
		reverse(s.begin(), s.end());
		int a = 0;
		int flag = 0;
		for (auto x : s)
		{
			if (x == 'A')
				a++;
			if (x == 'Q')
				a--;
			if (a < 0)
			{
				cout << "No" << endl;
				flag = 1;
				break;
			}
		}
		if(!flag)
		cout << "Yes" << endl;
	}
}

B

核心思路:这个题目其实想思路并不困难,观察下规律就出来了,写代码稍微困难点。刚开始想偏了,以为需要双指针,其实就是一个规律题。这个选取跨度长度比较关键,选择n/2最好,这样1最后一个数就方便一点,如果是n则需要再进行处理

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int N = 1e5+10;//表示的是高精度位数
char s[N];
int vis[N];
void solve()
{
	int n;
	cin >> n;
	int t = n / 2;
	for (int i = 1;i <= t;i++)
	{
		cout << i + t << " ";
		cout << i << " ";
	}
	if (n % 2 == 1)
		cout << n << endl;
	else
		cout << endl;
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

C1

核心思路:这里我们先统计处前缀和sum,然后我要注意一个点,那就是\(a_i\)要么是-1,要么是1.然后我们想怎么可以通过合并来改变sum的值。我们就从最基本的合并两个数来分析,这两个数最多只有四种组合情况。比如-1,1.原来的sum=0,合并后是不是等于-2,所以会造成sun-=2;接下来几种情况依然是这么分析,所以我们可以进行以下分类:

  1. sum>0
  • \(a_i=-1,a_{i+1}=1\)

  • \(a_i=1,a_{i+1}=1\)

  1. sum<0
  • \(a_i=1,a_{i+1}=-1\)

  • \(a_i=-1,a_{i+1}=1\)

这样分类就会不重不漏了,然后我们可以设立一个数组记录我们更新完之后的下标,其实情况就选一个数就好了,因为题目是允许的。这个数组的更新是值得学习的

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int N = 1e7 + 10;//表示的是高精度位数
int n, a[N], ne[N];
void solve()
{
    int n;
    cin >> n;
    int sum = 0;
    int res = n;
    for (int i = 1;i <= n;i++)
        cin >> a[i];
    for (int i = 1;i <= n;i++)
    {
        sum += a[i];
        ne[i] = i;
    }
    if (abs(sum) & 1)
    {
        cout << -1 << endl;
        return;
    }
    for (int i = 1; i < n; i++)
    {
        if (sum < 0)
        {
            if (a[i] == 1 && a[i + 1] == -1)
            {
                ne[i] = i + 2;
                i++;
                sum += 2;
                res--;
            }
            else if (a[i] == -1 && a[i + 1] == -1)
            {
                ne[i] = i + 2;
                sum += 2;
                i++;
                res--;
            }
        }
        else if (sum > 0)
        {
            if (a[i] == -1 && a[i + 1] == 1)
            {
                ne[i] = i + 2;
                sum -= 2;
                i++;
                res--;
            }
            else if (a[i] == 1 && a[i + 1] == 1)
            {
                ne[i] = i + 2;
                sum -= 2;
                i++;
                res--;
            }
        }
        if (sum == 0) break;
    }
    cout << res << '\n';
    for (int i = 1; i <= n; i++)
    {
        if (ne[i] == i) cout << i << " " << i << '\n';
        else
        {
            cout << i << " " << ne[i] - 1 << '\n';
            i = ne[i] - 1;
        }
    }
}
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
}

C2

核心思路:这一题是和上一题差不多的。大同小异,就是需要多讨论一种情况.

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int N = 1e7 + 10;//表示的是高精度位数
int n, a[N], ne[N];
void solve()
{
    int n;
    cin >> n;
    int sum = 0;
    int res = n;
    for (int i = 1;i <= n;i++)
        cin >> a[i];
    for (int i = 1;i <= n;i++)
    {
        sum += a[i];
        ne[i] = i;
    }
    if (abs(sum) & 1)//因为只会将sum+=2或者-=2
    {
        cout << -1 << endl;
        return;
    }
    for (int i = 1; i < n; i++)
    {
        if (sum < 0)
        {
            if (a[i] == 1 && a[i + 1] == -1)
            {
                ne[i] = i + 2;
                i++;
                sum += 2;
                res--;
            }
            else if (a[i] == -1 && a[i + 1] == -1)
            {
                ne[i] = i + 2;
                sum += 2;
                i++;
                res--;
            }
            else if (a[i] == 0 && a[i + 1] == -1)//为什么这么省掉了(-1,0)这种情况呢,我们使用反证法会发现压根不会改变sum的值所以不需要讨论
            {
                ne[i] = i + 2;
                sum += 2;
                i++;
                res--;
            }
        }
        else if (sum > 0)
        {
            if (a[i] == -1 && a[i + 1] == 1)
            {
                ne[i] = i + 2;
                sum -= 2;
                i++;
                res--;
            }
            else if (a[i] == 1 && a[i + 1] == 1)
            {
                ne[i] = i + 2;
                sum -= 2;
                i++;
                res--;
            }
            else if (a[i] == 0 && a[i + 1] == 1)
            {
                ne[i] = i + 2;
                sum -= 2;
                i++;
                res--;
            }
            else if (a[i] == 0 && a[i + 1] == 1)
            {
                ne[i] = i + 2;
                sum -= 2;
                i++;
                res--;
            }
        }
        if (sum == 0) break;
    }
    cout << res << '\n';
    for (int i = 1; i <= n; i++)
    {
        if (ne[i] == i) cout << i << " " << i << '\n';
        else
        {
            cout << i << " " << ne[i] - 1 << '\n';
            i = ne[i] - 1;
        }
    }
}
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
}

D

核心思路:其实我们需要先观察阶乘分解的规律:例如:\(4!=1!+1!+2!+2!+3!+3!+3!\),所以我们

从前往后枚举1-n中的所有数,如果都满足数x的阶乘出现的次数可以被x+1整除,那么就说明是成立的。

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int N = 1e7 + 10;//表示的是高精度位数
int cnt[N];
int a[N];
void solve()
{
	int n, x;
	cin >> n >> x;
	for (int i = 1;i <= n;i++)
		cin >> a[i];
	for (int i = 1;i <= n;i++)
		cnt[a[i]]++;
	for (int i = 1;i < x;i++)
	{
		if (cnt[i] % (i + 1))
		{
			cout << "No" << endl;
			return;
		}
		cnt[i + 1] += cnt[i] / (i + 1);
	}
		cout << "Yes" << endl;
}
int main()
{
	solve();
}

E

核心思路:这是个dp问题

  1. 集合定义:dp[i]表示还有i个位置需要进行交换。i是指我们没有排号的点数。

  2. 集合划分:我们我们把这个集合划分为两个状态,一种是我们选到了第i个点,首先分析我们选到了第i个点的概率:\(i*i/(C_{n}^{2})\),然后我们分析为什么分子是i*i,因为我们那个点的数字要么是1,要么是0,我们还需要直到如果有i个i没有排好,那么肯定就对应i个0也没有排好,所以总数是\(i*i\).然后没有选到的点的数目就一定是:\(1-(i*i)/(C_{n}^{2})\).

  3. 状态转移方程:\(dp[i]=dp[i-1]*(i*i)/(C_{n}^{2})+dp[i]*(1-(i*i)/C_{n}^{2})+1\),化简可以得:dp[i]=dp[i-1]+\(C_{n}^{2}/(i*i)\)

接下来就需要统计下有多少个需要交换的数字就好了,这个也很简单,直接看代码就好了。

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int N = 1e7 + 10;//表示的是高精度位数
int mod = 998244353;
int a[N];
int qmi(int a, int b) {
	int res = 1;
	while (b)
	{
		if (b & 1)
			res = res * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return res;
}
void solve()
{
	int n;
	cin >> n;
	int res = 0;
	int ans = 0;
	int cnt = 0;
	for (int i = 1;i <= n;i++)
	{
		cin >> a[i];
		cnt += (a[i] == 0);
	}
	for (int i = 1;i <= cnt;i++)
	{
		if (a[i] != 0)
			res++;
	}
	for (int i = 1;i <= res;i++)
	{
		ans = (ans + (n * (n - 1) / 2)%mod * qmi(i * i%mod, mod - 2) % mod) % mod;//这里用到了费马小定理应为i*i是肯定和mod互为质数的
	}
	cout << ans << endl;
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

链接

posted @ 2022-11-25 15:00  努力的德华  阅读(36)  评论(0)    收藏  举报