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;接下来几种情况依然是这么分析,所以我们可以进行以下分类:
- sum>0
-
\(a_i=-1,a_{i+1}=1\)
-
\(a_i=1,a_{i+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问题
-
集合定义:dp[i]表示还有i个位置需要进行交换。i是指我们没有排号的点数。
-
集合划分:我们我们把这个集合划分为两个状态,一种是我们选到了第i个点,首先分析我们选到了第i个点的概率:\(i*i/(C_{n}^{2})\),然后我们分析为什么分子是i*i,因为我们那个点的数字要么是1,要么是0,我们还需要直到如果有i个i没有排好,那么肯定就对应i个0也没有排好,所以总数是\(i*i\).然后没有选到的点的数目就一定是:\(1-(i*i)/(C_{n}^{2})\).
-
状态转移方程:\(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();
}
}

浙公网安备 33010602011771号