给定长度为 n n n 的只包括 − 1 -1 −1 和 1 1 1 的序列。进行一次操作:选定 i i i ,使 a i a_i ai 和 a i + 1 a_{i+1} ai+1 变为相反数。询问操作一次后,序列的和的最大值
如果选择的两个数均为 − 1 -1 −1 ,会使和增加 4 4 4;
如果选择的两个数一个是 1 1 1 ,一个是 − 1 -1 −1,和不变;
如果选择的两个数均为 1 1 1,会使和减小 4 4 4
#include
using namespace std;
#define fi first
#define se second
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
int n;
int a[maxn];
void solve(){
cin >> n;
int sum = 0;
for(int i = 1; i <= n; i++){
cin >> a[i];
sum += a[i];
}
int flag1 = 0, flag2 = 0;
for(int i = 2; i <= n; i++){
if(a[i] == -1 && a[i-1] == -1){
flag1 = 1;
break;
}
if(a[i] != a[i-1])
flag2 = 1;
}
if(flag1)
sum += 4;
else if(!flag2)
sum -= 4;
//cout << "ans = " ;
cout << sum << endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T--)
solve();
return 0;
}
给定长度为 n n n 的一个排列 p p p,大小为 m m m 的数组 a a a , a a a 中元素互不相同
数组 a a a 是 不好的 当且仅当 对任意 1 ≤ i < m 1\le i < m 1≤i<m ,都有 p o s ( a i ) < p o s ( a i + 1 ) ≤ p o s ( a i ) + d pos(a_i) < pos(a_{i+1}) \le pos(a_i)+d pos(ai)<pos(ai+1)≤pos(ai)+d 。 p o s ( x ) pos(x) pos(x) 是 x x x 在排列 p p p 中的位置。
每次操作可以交换排列 p p p 中的两个相邻元素,询问是数组 a a a 成为 好的 的最少操作次数。
依次考虑每一组 a i a_i ai 和 a i + 1 a_{i+1} ai+1 。
如果不满足条件,则答案为 0 0 0 ,因为此时数组 a a a 已经是好的;
如果满足条件,通过操作使条件不满足。可以将 a i + 1 a_{i+1} ai+1 放到 a i a_i ai 的前边,操作次数为 p o s ( a i + 1 ) − p o s ( a i ) pos(a_{i+1}) - pos(a_i) pos(ai+1)−pos(ai) 。也可以使 a i + 1 a_{i+1} ai+1 放到后边,操作次数为 p o s ( a + i ) + d + 1 − p o s ( a i + 1 ) pos(a+i)+d+1-pos(a_{i+1}) pos(a+i)+d+1−pos(ai+1)。
特别注意,当 d > = n − 1 d >= n-1 d>=n−1 时,无法通过第二种方法使条件不满足
#include
using namespace std;
#define fi first
#define se second
const int maxn = 5e5+10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
int n, m, d;
int p[maxn], a[maxn], pos[maxn];
void solve(){
cin >> n >> m >> d;
int ans = INF;
for(int i = 1; i <= n; i++){
cin >> p[i];
pos[p[i]] = i;
}
for(int i = 1; i <= m; i++)
cin >> a[i];
for(int i = 1; i < m; i++){
if(pos[a[i]] < pos[a[i+1]] && pos[a[i+1]] <= pos[a[i]]+d){
int c1 = pos[a[i+1]]-pos[a[i]];
int c2 = pos[a[i]]+d+1-pos[a[i+1]];
if(d >= n-1)
c2 = INF;
int c = min(c1, c2);
ans = min(ans, c);
}
else{
ans = 0;
break;
}
}
//cout << "ans = ";
cout << ans << endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T--)
solve();
return 0;
}
给定两个长度为 n n n 的字符串 a , b a, b a,b 。其中, a a a 中不同字符个数不超过10个。
给定一个初始空集合 Q Q Q 。每次操作可以选定 i i i,将 a i a_i ai 放到集合 Q Q Q 中,并用任意小写字母代替 a i a_i ai。集合 Q Q Q 中元素个数 不能超过 k k k
询问 ( l , r ) (l,r) (l,r) 的个数, ( l , r ) (l,r) (l,r) 满足 a [ l , r ] = b [ l , r ] a[l,r] = b[l,r] a[l,r]=b[l,r]。
首先看到 a a a 中字符种类不超过 10 10 10,选择 k k k 个的话,最多 C ( 10 , 5 ) = 252 C(10,5) = 252 C(10,5)=252 种情况。
每种情况如果可以在 O ( n ) O(n) O(n) 时间内计算结果的话,就可以解决。
考虑长度为 l e n len len 的 a , b a,b a,b 相同的子串。对答案的贡献为 l e n ( l e n + 1 ) 2 \frac{len(len+1)}{2} 2len(len+1) 。因此,对于每种情况,遍历一次 a , b a,b a,b,计算结果即可。
#include
using namespace std;
#define fi first
#define se second
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
const int maxs = 1023;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
ll f(int x){
ll res = x;
return res*(res+1)/2;
}
char a[maxn], b[maxn];
int n, k;
vector<int> s[12];
int cal(int x){
int cnt = 0;
while(x){
if(x&1)
cnt++;
x = x >> 1;
}
return cnt;
}
void init(){
for(int i = 0; i <= maxs; i++){
int cnt = cal(i);
s[cnt].push_back(i);
/*
for(int j = cnt; j <= 10; j++)
s[j].push_back(i);*/
}
}
int vis[30];
map<int, int> mp;
bool check(int state, int x){
if((state & (1<<x)) == 0)
return false;
else
return true;
}
void solve(){
cin >> n >> k;
cin >> a+1 >> b+1;
memset(vis, 0, sizeof(vis));
mp.clear();
ll ans = 0;
for(int i = 1; i <= n; i++){
int s = a[i]-'a';
vis[s] = 1;
}
for(int i = 0; i <= 25; i++){
if(!vis[i])
continue;
int cnt = 0;
for(int j = 0; j < i; j++)
if(vis[j])
cnt++;
mp[i] = cnt;
}
for(int ii = 0; ii < s[k].size(); ii++){
int state = s[k][ii];
int len = 0;
ll res = 0;
for(int i = 1; i <= n; i++){
int x = a[i]-'a';
if(a[i] == b[i]){
len++;
}
else if(check(state, mp[x])){
len++;
}
else{
res += f(len);
len = 0;
}
}
if(a[n] == b[n] || check(state, mp[(int)a[n]-'a']))
res += f(len);
ans = max(res, ans);
}
//cout << "ans = ";
cout << ans << endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
init();
int T;
cin >> T;
while(T--)
solve();
return 0;
}
给定长度为 n n n 的 01 01 01 串 a , b a,b a,b 。每次操作随机选 i i i ,翻转 a i a_i ai
询问 a a a 和 b b b 第一次相等的操作次数的期望
令 f i f_i fi 为 由 i − 1 i-1 i−1 处相同,变为 i i i 处相同的期望次数。
如果此时有 i i i 处相同。有 n − i n \frac{n-i}{n} nn−i 概率操作一次;有 i n \frac{i}{n} ni 的选中相同的位置,变成 i − 1 i-1 i−1 处相同,然后需要操作 f i + f i + 1 f_i+f_{i+1} fi+fi+1 次变为 i + 1 i+1 i+1 处相同。
因此 f i + 1 = n − i n + i n × ( 1 + f i + f i + 1 ) f_{i+1} = \frac{n-i}{n} +\frac{i}{n}\times(1+f_i+f_{i+1}) fi+1=nn−i+ni×(1+fi+fi+1)
整理得: f i + 1 = 1 + i n − i × ( 1 + f i ) f_{i+1} = 1+\frac{i}{n-i}\times(1+f_i) fi+1=1+n−ii×(1+fi)
如果初始 a a a 和 b b b 有 k k k 处相同,答案为 ∑ i = k + 1 n f i \sum\limits_{i=k+1}\limits^nf_i i=k+1∑nfi
#include
using namespace std;
#define fi first
#define se second
const int maxn = 1e6+10;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
ll qpow(ll a, ll b){
ll res = 1;
while(b){
if(b&1)
res = res*a%mod;
b = b >> 1;
a = a*a%mod;
}
return res%mod;
}
ll inv(ll a){
return qpow(a, mod-2);
}
ll f[maxn];
char a[maxn], b[maxn];
void solve(){
int n;
cin >> n;
cin >> a+1 >> b+1;
ll sam = 0;
for(int i = 1; i <= n; i++)
if(a[i] == b[i])
sam++;
f[1] = 1;
for(int i = 1; i < n; i++){
f[i+1] = 1 + i*inv(n-i)%mod*(f[i]+1);
f[i+1] %= mod;
}
ll sum = 0;
for(int i = sam+1; i <= n; i++){
sum += f[i];
sum %= mod;
}
sum = ((sum%mod)+mod)%mod;
cout << sum << endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T--)
solve();
return 0;
}