Codeforces Round #732 (Div. 2) A~D题解
本场链接:Codeforces Round #732 (Div. 2)
闲话
感觉C/D也没很简单,需要一些观察.由于E/F难度严重超出d2就没做了(也许某天会补进来
A. AquaMoon and Two Arrays
数据范围不大,考虑直接做:
首先不难观察到操作并不会改变整个数组的值,所以两个数组之和如果不相同则一定无解.
其次可以如此模拟整个过程:记录当前需要的差值,如果\(a[i] > b[i]\)则说明某个数需要被增加\(a[i] - b[i]\)反之类似,记录一个差值\(val\),在做完整个过程之后如果\(val == 0\)则表明整个数组的差异是平衡的,即有解.反之无解.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
#define x first
#define y second
const int N = 105;
int a[N],b[N];
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n;scanf("%d",&n);
forn(i,1,n) scanf("%d",&a[i]);
forn(i,1,n) scanf("%d",&b[i]);
vector<pii> op;
bool ok = 1;
forn(i,1,n)
{
while(a[i] > b[i])
{
int j = 1;
while(j <= n && a[j] >= b[j]) ++j;
if(a[j] >= b[j])
{
ok = 0;
break;
}
op.push_back({i,j});
--a[i];++a[j];
}
if(!ok) break;
}
forn(i,1,n) if(a[i] != b[i]) ok = 0;
if(!ok) puts("-1");
else
{
printf("%d\n",(int)op.size());
for(auto& _ : op) printf("%d %d\n",_.x,_.y);
}
}
return 0;
}
B. AquaMoon and Stolen String
在已经做完了的数组里(长度是\(2*n-1\)的),除了被孤立的串,每个串的每个字符相当于被增加了一个.所以被孤立的那个串的每个元素在他的那一列一定是只出现了奇数个的.找出这样的一个串就是答案.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
const int N = 2e5+7;
string s[N];
bool ans[N];
int main()
{
Angel_Dust;
int T;cin >> T;
while(T--)
{
int n,m;cin >> n >> m;
n = 2 * n - 1;
forn(i,1,n / 2 + 1) ans[i] = 1;
forn(i,1,n) cin >> s[i];
forn(i,0,m - 1)
{
map<char,int> st;
forn(j,1,n) ++st[s[j][i]];
forn(j,1,n / 2 + 1) if(st[s[j][i]] % 2 == 0) ans[j] = 0;
}
string res;
forn(i,1,n / 2 + 1) if(ans[i]) res = s[i];
cout << res << endl;
}
return 0;
}
C. AquaMoon and Strange Sort
由于要保证操作次数都是偶数,所以对两个元素进行操作,相当于没动,最少需要操作三个元素,可以发现对于三个元素进行操作之后,相当于是把三个元素翻转了,于是可以想到:对于任何两个位置是奇数/偶数的元素,交换他们两个是可以保证操作是正确的.即:对任何位置奇偶性相同的元素是可以任意交换的:将所有元素按奇偶位置抠出来,再把两个数组合并,如果最后得到的数组是不降的,则说明有解.反之无解.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
const int N = 1e5+7;
int a[N];
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n;scanf("%d",&n);
forn(i,1,n) scanf("%d",&a[i]);
vector<int> odd,even;
forn(i,1,n) if(i % 2) odd.push_back(a[i]);else even.push_back(a[i]);
sort(odd.begin(),odd.end());sort(even.begin(),even.end());
reverse(odd.begin(),odd.end());reverse(even.begin(),even.end());
vector<int> res;
while(!odd.empty() || !even.empty())
{
if(!odd.empty())
{
res.push_back(odd.back());
odd.pop_back();
}
if(!even.empty())
{
res.push_back(even.back());
even.pop_back();
}
}
bool ok = 1;
forn(i,0,(int)res.size() - 2) if(res[i] > res[i + 1]) ok = 0;
if(!ok) puts("NO");
else puts("YES");
}
return 0;
}
D. AquaMoon and Chess
不难想到应该把:11
看做是一个整体进行操作.具体来说,从左到右依次把每个11
合并到一个组里(若前者是个1
且自己也是,同时前者不在某个组里,则合并为一个组),现在整个序列里只有11;1;0
.
我们不妨把1
也看做是可以进行移动的,因为在移动了之后,1
的形态也不会发生变化,如此可以看做是把序列里所有的1
都删去(同时不影响方案数的计算).进一步的,因为现在在求每个11
相对于\(0\)的位置,所以也相当于求把每个11
插入相对于每个\(0\)的位置里,设有\(m\)个组和\(z\)个\(0\),那么原问题的方案数等价于把\(m\)个球分成\(n+1\)组的方案数,根据隔板法\(ans = \begin{pmatrix}m + z\\m\end{pmatrix}\).故预处理逆元即可计算.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
const int N = 2e5+7,MOD = 998244353;
bool st[N];
char s[N];
int fact[N],infact[N];
int qpow(int a,int b,int MOD)
{
int res = 1;
while(b)
{
if(b & 1) res = 1ll * res * a % MOD;
a = 1ll * a * a % MOD;
b >>= 1;
}
return res;
}
int C(int n,int m)
{
if(n < m) return 0;
int res = fact[n];
res = 1ll * res * infact[m] % MOD;
res = 1ll * res * infact[n - m] % MOD;
return res;
}
int main()
{
fact[0] = infact[0] = 1;
forn(i,1,N - 1) fact[i] = 1ll * i * fact[i - 1] % MOD,infact[i] = 1ll * infact[i - 1] * qpow(i,MOD - 2,MOD) % MOD;
int T;scanf("%d",&T);
while(T--)
{
int n;scanf("%d",&n);
forn(i,1,n) st[i] = 0;
scanf("%s",s + 1);
int m = 0,z = 0;
forn(i,1,n) if(s[i] == '0') ++z;
forn(i,1,n - 1)
{
if(s[i] == '1' && s[i + 1] == '1' && !st[i])
{
st[i] = 1;
st[i + 1] = 1;
++m;
}
}
printf("%d\n",C(m + z,z));
}
return 0;
}