题意:给定一个两个长度为n的数字序列A,B,判断是否可以通过对A进行若干次以下操作得到B。
操作:任选两个下标1<=i!=j<=n,a[i]++,b[j]–
思路:直接判断需要加的次数和减的次数是否一致即可
#include <bits/stdc++.h>
#define int long long
#define pii pair<int, int>
using namespace std;
const int N = 1e6 + 10;
inline void solve() {
int n, ans = 0, k = 0;
scanf("%lld", &n);
vector<int> a(n), b(n), c, d;
c.clear(); d.clear();
for(int i = 0; i < n; i++) scanf("%lld", &a[i]);
for(int i = 0; i < n; i++) scanf("%lld", &b[i]);
for(int i = 0; i < n; i++) {
if(a[i] > b[i]) {
for(int j = 1; j <= a[i] - b[i]; j++)
c.push_back(i);
}
else if(a[i] < b[i]) {
for(int j = 1; j <= b[i] - a[i]; j++)
d.push_back(i);
}
}
if(c.size() - d.size() != 0) cout << -1 << endl;
else {
cout << c.size() << endl;
for(int i = 0; i < c.size(); i++) {
cout << c[i] + 1 << " " << d[i] + 1 << endl;
}
}
return ;
}
signed main() {
int t; scanf("%lld", &t);
while(t--) solve();
return 0;
}
题意:
给n(n为奇数)个长度为m的字符串,并按照以下规则打乱n-1个字符串,输出未被打乱的字符串
打乱规则:对于任意两个未被打乱规则的字符串s1,s2,选择一些位置i(1 <= i <= m),交换s1[i]和s2[i]的字母。
例如m=6,对于两个字符串"abcdef"和"xyzklm",选择位置2,3和6,把’b’换成’y’, ‘c’换成’z’, ‘f’换成’m’。得到的字符串将是"ayzdem"和"xbcklf"
思路:按照交换规则,对于n个字符串,字符串第i个位置的字符无论怎么变换,它出现的次数是不变的,经过变换以后,一定是等于0的,于是通过判断字符出现次数不为0时,即为未做改变的字符串的第i个位置字符。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10;
int n, m;
string s[N], t[N];
inline void solve() {
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> s[i];
for(int i = 1; i <= n - 1; i++) cin >> t[i];
unordered_map<char, int> cnt;
vector<char> ans;
for(int i = 0; i < m; i++) {
for(int j = 1; j <= n; j++) cnt[s[j][i]]++;
for(int j = 1; j <= n - 1; j++) cnt[t[j][i]]--;
for(int j = 1; j <= n; j++) {
if(cnt[s[j][i]]) {
ans.push_back(s[j][i]);
cnt[s[j][i]] = 0; break;
}
}
}
for(int i = 0; i < ans.size(); i++) cout << ans[i]; cout << endl;
return ;
}
signed main() {
int t; cin >> t;
while(t--) solve();
return 0;
}
题意:给定n个数,可以进行任意次相邻数交换,目标序列是不递增序列,问对于每个数能否用偶数次操作使得它们回到目标位置上。
思路: 由于n个数要经过偶数次操作使它们回到目标位置,那么奇数位的元素必须回到奇数位,偶数位必须回到偶数位,那么可以通过判断原本在奇数位的元素在排完序以后是否也在奇数位即可。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10;
inline void solve() {
int n; cin >> n;
vector<int> x(n);
for(int i = 0; i < n; i++) cin >> x[i];
unordered_map<int, int> cnt;
for(int i = 0; i < n; i++) {
if(i & 1) cnt[x[i]]++;
else cnt[x[i]]--;
}
sort(x.begin(), x.end());
for(int i = 0; i < n; i++) {
if(i & 1) cnt[x[i]]--;
else cnt[x[i]]++;
}
for(int i = 0; i < n; i++)
if(cnt[x[i]]) {
cout << "No" << endl;
return ;
}
cout << "Yes" << endl;
return ;
}
signed main() {
int t; cin >> t;
while(t--) solve();
return 0;
}
题意:给一个由01组成的字符串s,对于每一个字符s[i] = ‘1’,有以下操作
①:i+2≤n并且s[i+1] = ‘1’,那么s[i +2]可以等于’1’
②:i - 2 >= 1并且s[i-1]=‘1’,那么s[i-2]可以等于’1’
请问字符串有多少种变化方式
思路:组合数规律,数成对的1的个数n,0的个数m,答案是C(n+m,n)
代码:
#include <bits/stdc++.h>
#define int long long
#define pii pair<int, int>
using namespace std;
const int N = 1e6 + 10, mod = 998244353;
inline int qpow(int a, int b) {
int res = 1;
while (b)
{
if (b & 1) res = (res * a) % mod;
a = a * a % mod, b >>= 1;
}
return res % mod;
}
inline int work(int n, int m) {
int s = 1, c = 1;
for (int i = 1; i <= m; i+=1)
s = (s * i) %mod; //计算分母
for (int i = n - m + 1; i <= n; i++)
c = (c * i) % mod; //计算分子
return (c * qpow(s, mod - 2)) % mod; //求出值
}
inline void solve() {
int n; cin >> n;
int s1 = 0, s2 = 0;
string s; cin >> s;
for(int i = 0; i < s.size(); i++) {
if(s[i] == '0') s1++;
else if(s[i] == '1' && s[i + 1] == '1') {
s2++; i++;
}
}
cout << work(s1 + s2, s1) << endl;
return ;
}
signed main() {
int t; scanf("%lld", &t);
while(t--) solve();
return 0;
}