目录
A. Unit Array
Given an array a of length n, which elements are equal to −1−1 and 11. Let's call the array a good if the following conditions are held at the same time:
- a1+a2+…+an≥0
- a1⋅a2⋅…⋅an=1
In one operation, you can select an arbitrary element of the array ai and change its value to the opposite. In other words, if ai=−1, you can assign the value to ai:=1, and if ai=1, then assign the value to ai:=−1.
Determine the minimum number of operations you need to perform to make the array a good. It can be shown that this is always possible.
Input
Each test consists of multiple test cases. The first line contains a single integer t (1≤t≤500) — the number of test cases. The description of the test cases follows.
The first line of each test case contains a single integer n (1≤n≤100) — the length of the array a.
The second line of each test case contains n integers a1,a2,…,an (ai=±1) — the elements of the array a.
Output
For each test case, output a single integer — the minimum number of operations that need to be done to make the a array good.
Example
input
7
4
-1 -1 1 -1
5
-1 -1 -1 1 1
4
-1 1 -1 1
3
-1 -1 -1
5
1 1 1 1 1
1
-1
2
-1 -1
output
1 1 0 3 0 1 2
题意:
给一个由 1 和 -1 构成的数组,每次可以把任意一个数变成相反数,求满足条件的最小操作次数
1. 数组和>=0
2. 数组积为1
思路:
每次把-1变成1,和+2,和变正后,如果积为-1则再变一次
代码:
#include<bits/stdc++.h>
#define endl '\n'
#define debug(x) cout<<#x<<'='<<x<<endl;
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
const int INF=0x3f3f3f3f;
void solve(){
int n;
cin>>n;
int sum=0;
int mul=1;
while(n--){
int a;
cin>>a;
mul*=a;
sum+=a;
}
int ans=0;
if(sum<0){
sum*=-1;
ans=(sum+1)/2;
}
if(ans%2==1)mul*=-1;
if(mul==-1)ans++;
cout<<ans<<endl;
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
B. Maximum Strength
Fedya is playing a new game called "The Legend of Link", in which one of the character's abilities is to combine two materials into one weapon. Each material has its own strength, which can be represented by a positive integer x The strength of the resulting weapon is determined as the sum of the absolute differences of the digits in the decimal representation of the integers at each position.
Fedya has an unlimited supply of materials with all possible strengths from L to R, inclusive. Help him find the maximum possible strength of the weapon he can obtain.
Input
Each test contains multiple test cases. The first line contains the number of test cases t (1≤t≤500). The description of the test cases follows.
The first line of each test case contains two integers L and R (1≤L≤R<10100) — the decimal representation of the integers representing the minimum and maximum strength of the materials that Fedya has. It is guaranteed that the integers L and R do not contain leading zeros.
Note that the input data may not fit into standard 3232-bit or 6464-bit integer data types.
Output
For each test case print one integer — the maximum possible strength of the weapon that Fedya can obtain from the given materials.
Example
input
6
53 57
179 239
13 37
132228 132228
54943329752812629795 55157581939688863366
88 1914
output
4 19 11 0 163 28
题意:
给一个区间 [ L,R ] ,选区间内两个数,使得它们 每一位之差的绝对值 的和最小,长度不同补前导0
思路:
要使每一位上的差值最大,尽可能都是0和9,贪心,如果 L 和 R 的长度不同,则 L 用9补齐位数,取99999,R第一位不变,剩下取0,即 x00000,符合题意
如果 L 和 R 的长度相同,前面相同的位不用管,后面若有不同,第一位不变,后面L全取9,R全取0
代码:
#include<bits/stdc++.h>
#define endl '\n'
#define debug(x) cout<<#x<<'='<<x<<endl;
using namespace std;
#define int long long
typedef pair<int,int> pii;
typedef long long ll;
const int INF=0x3f3f3f3f;
void solve(){
string s1,s2;
cin>>s1>>s2;
if(s1==s2){
cout<<0<<endl;
return;
}
int len1=s1.length();
int len2=s2.length();
int ans=0;
if(len1<len2){
ans=s2[0]-'0'+9*(len2-1);
cout<<ans<<endl;
return;
}
int pos=-1;
for(int i=0;i<len1;i++){
if(s1[i]==s2[i])continue;
pos=i;
break;
}
ans+=s2[pos]-s1[pos];
pos++;
ans+=9*(len1-pos);
cout<<ans<<endl;
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
C. Game with Reversing
Alice and Bob are playing a game. They have two strings S and T of the same length n consisting of lowercase latin letters. Players take turns alternately, with Alice going first.
On her turn, Alice chooses an integer i from 1 to n, one of the strings S or T, and any lowercase latin letter c, and replaces the i-th symbol in the chosen string with the character c.
On his turn, Bob chooses one of the strings S or T, and reverses it.
The game lasts until the strings S and T are equal. As soon as the strings become equal, the game ends instantly.
Define the duration of the game as the total number of moves made by both players during the game. For example, if Alice made 2 moves in total, and Bob made 11 move, then the duration of this game is 3.
Alice's goal is to minimize the duration of the game, and Bob's goal is to maximize the duration of the game.
What will be the duration of the game, if both players play optimally? It can be shown that the game will end in a finite number of turns.
Input
Each test contains multiple test cases. The first line contains the number of test cases t (1≤t≤104). The description of the test cases follows.
The first line of each test case contains a single integer n (1≤n≤105) — the length of the strings S and T
The second line of each test case contains a string S of length n consisting of lowercase latin letters.
The third line of each test case contains a string T of length n consisting of lowercase latin letters.
It is guaranteed that the sum of n over all test cases does not exceed 105105.
Output
For each test case, output a single number on a separate line — the duration of the described game, if both players play optimally.
Example
input
7
5
abcde
abxde
5
hello
olleo
2
ab
cd
7
aaaaaaa
abbbbba
1
q
q
6
yoyoyo
oyoyoy
8
abcdefgh
hguedfbh
output
1 2 3 9 0 2 6
题意:
给两个字符串,轮流进行两个操作,求使两个字符串相等需要的最少次数
操作1:改变某个字符串的某个字符;操作2:翻转某个字符串
思路:
发现操作二作用于哪个字符串都一样,贪心,找出顺着比和倒着比 不同字符的个数,然后分别讨论,取最少次数
代码:
#include<bits/stdc++.h>
#define endl '\n'
#define debug(x) cout<<#x<<'='<<x<<endl;
using namespace std;
#define int long long
typedef pair<int,int> pii;
typedef long long ll;
const int INF=0x3f3f3f3f;
void solve(){
int n;
cin>>n;
string s1,s2;
cin>>s1>>s2;
int cnt1=0,cnt2=0;
for(int i=0;i<n;i++){
cnt1+=(s1[i]!=s2[i]); //统计不同字符个数
cnt2+=(s1[i]!=s2[n-1-i]);
}
if(cnt1==0){
cout<<0<<endl;
return;
}
if(cnt2==0){
cout<<2<<endl;
return;
}
int ans=2*cnt1-(cnt1%2==1); //改成和s2一样,若修改个数为奇数次,最后一次不用翻转
ans=min(ans,2*cnt2-(cnt2%2==0)); //改成和s2反过来一样,若偶数次,则最后一次不用翻转
cout<<ans<<endl;
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
D. Survey in Class(区间减法)
Zinaida Viktorovna has n students in her history class. The homework for today included m topics, but the students had little time to prepare, so i-th student learned only topics from lito ri inclusive.
At the beginning of the lesson, each student holds their hand at 0. The teacher wants to ask some topics. It goes like this:
- The teacher asks the topic k.
- If the student has learned topi k, then he raises his hand by 11, otherwise he lower it by 11.
Each topic Zinaida Viktorovna can ask no more than one time.
Find the maximum difference of the heights of the highest and the lowest hand that can be in class after the survey.
Note that the student's hand can go below 00.
Input
Each test contains multiple test cases. The first line contains the number of test cases t (1≤t≤104). The description of the test cases follows.
The first line of each test case contains two integers n and m(2≤n≤105,1≤m≤109,) — the number of students and the number of topics, respectively.
Each of the next n lines of each test case contain two integers li and ri (1≤li≤ri≤m) — the endpoints of the segment of topics that i-th student has learned.
It is guaranteed that the sum of n over all test cases does not exceed 105105.
Output
For each test case, print one integer — the maximum difference of the heights of the highest and the lowest hand that can be in the class after the survey.
Example
input
6
4 8
2 6
4 8
2 7
1 5
3 3
1 3
2 3
2 2
3 5
1 5
1 5
1 5
3 5
1 1
3 3
5 5
4 7
1 7
1 3
3 3
4 5
2 4
1 3
2 4
output
6 4 0 2 12 2
题意:
给若干个区间,求 [ L1,R1 ] 减去 [ L2,R2 ] 后的最大值
思路:
处理出来每个区间的左端点右端点,以及最大的左端点和最小的右端点
初始化ans为最大区间长度-最小区间长度
然后枚举区间,区间剩余最大有两种可能,一种是减去maxl,一种是减去minr,一定是交叉的(如果包含,一定小于等于初始的ans)
也可以这么理解:区间减去一个区间剩余的部分有三种可能,一种是剩左边,一种是剩右边,一种是两边都剩,前两种情况枚举找出最小值,第三种情况的最小值是maxlen - minlen
代码:
#include<bits/stdc++.h>
#define endl '\n'
#define debug(x) cout<<#x<<'='<<x<<endl;
using namespace std;
#define int long long
typedef pair<int,int> pii;
typedef long long ll;
const int INF=0x3f3f3f3f;
void solve(){
int n,m;
cin>>n>>m;
vector<int>l(n+1),r(n+1),len(n+1);
for(int i=1;i<=n;i++){
cin>>l[i]>>r[i];
len[i]=r[i]-l[i]+1;
}
int ans=*max_element(len.begin()+1,len.end())-*min_element(len.begin()+1,len.end());
int maxl=*max_element(l.begin()+1,l.end()),minr=*min_element(r.begin()+1,r.end());
for(int i=1;i<=n;i++){
ans=max(ans,min(len[i],max(r[i]-minr,maxl-l[i])));
}
cout<<2*ans<<endl;
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
E. MEX of LCM(子区间枚举+前缀和思想)
You are given an array a of length n. A positive integer x is called good if it is impossible to find a subsegment†† of the array such that the lcm of all its elements is equal to x.
You need to find the smallest good integer.
A subsegment of the array a is a set of elements al,al+1,…,ar for some 1≤l≤r≤n. We will denote such subsegment as [l,r]
Input
Each test consists of multiple test cases. The first line of each test case contains a single integer t (1≤t≤5⋅104 — the number of test cases. The description of test cases follows.
The first line of each test case contains a single integer n (1≤n≤3⋅105) — the length of the array a
The second line of each test case contains n integers a1,a2,…,an (1≤ai≤109) — the elements of the array a.
It is guaranteed that the sum of n over all test cases does not exceed 3⋅105.
Output
For each test case, output a single integer — the smallest good integer.
Example
input
6
3
1 2 3
5
1 2 3 4 5
2
2 3
1
1000000000
12
1 8 4 2 3 5 7 2 9 10 11 13
12
7 2 5 4 2 1 1 2 3 11 8 9
output
4 7 1 1 16 13
题意:
给一个数组a,把a中所有 连续字段 的 lcm 构成一个集合,找出这个集合的mex
思路:
n的值是1e5,因为n以内的质因数个数是O(n)级别的,所以答案不会超过10*n,我们假设答案为1e7,所有超过答案的lcm对mex没有贡献,都是没用的,直接扔掉。
我们维护一个集合s,里面储存了所有出现过的lcm,通过集合s得到答案
我们可以通过枚举字段的终点得到所有的字段,而且我们发现以 i 结尾的所有lcm等于以 i-1 结尾的lcm和a[i]的lcm,通过维护一个集合pre,里面储存了以 i 结尾的所有字段的lcm,不断进行lcm得到新的pre,暴力转移一遍即可得到答案
代码:
#include<bits/stdc++.h>
#define endl '\n'
#define debug(x) cout<<#x<<'='<<x<<endl;
using namespace std;
#define int long long
typedef pair<int,int> pii;
typedef long long ll;
const int INF=0x3f3f3f3f;
ll gcd(ll x,ll y){
while(y^=x^=y^=x%=y);
return x;
}
ll lcm(ll x,ll y){
return x/gcd(x,y)*y;
}
void solve(){
int maxn=1e7;
int n;
cin>>n;
vector<int>a(n+1);
for(int i=1;i<=n;i++)cin>>a[i];
set<int>s,pre;
for(int i=1;i<=n;i++){
s.insert(a[i]);
set<int>tmp;
tmp.insert(a[i]);
for(auto j:pre){
int t=lcm(j,a[i]);
if(t>=maxn)continue;
s.insert(t);
tmp.insert(t);
}
pre.swap(tmp);
}
int ans=1;
while(s.count(ans))ans++;
cout<<ans<<endl;
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
F. Typewriter(思维)
Recently, Polycarp was given an unusual typewriter as a gift! Unfortunately, the typewriter was defective and had a rather strange design.
The typewriter consists of n cells numbered from left to right from 1to n, and a carriage that moves over them. The typewriter cells contain n distinct integers from 1 to n, and each cell i initially contains the integer pi. Before all actions, the carriage is at cell number 11 and there is nothing in its buffer storage. The cell on which the carriage is located is called the current cell.
The carriage can perform five types of operations:
- Take the integer from the current cell, if it is not empty, and put it in the carriage buffer, if it is empty (this buffer can contain no more than one integer).
- Put the integer from the carriage buffer, if it is not empty, into the current cell, if it is empty.
- Swap the number in the carriage buffer with the number in the current cell, if both the buffer and the cell contain integers.
- Move the carriage from the current cell i to cell i+1 (if i<n), while the integer in the buffer is preserved.
- Reset the carriage, i.e. move it to cell number 11, while the integer in the buffer is preserved.
Polycarp was very interested in this typewriter, so he asks you to help him understand it and will ask you q queries of three types:
- Perform a cyclic shift of the sequence p to the left by kj.
- Perform a cyclic shift of the sequence p to the right by kj.
- Reverse the sequence p.
Before and after each query, Polycarp wants to know what minimum number of carriage resets is needed for the current sequence in order to distribute the numbers to their cells (so that the number i ends up in cell number i).
Note that Polycarp only wants to know the minimum number of carriage resets required to arrange the numbers in their places, but he does not actually distribute them.
Help Polycarp find the answers to his queries!
Input
The first line contains a single integer n (1≤n≤4⋅105) — the number of cells.
The second line contains n distinct integers p1,p2,…,pn(1≤pi≤n — the initial arrangement of integers in the cells.
The third line contains a single integer q (0≤q≤4⋅105) — the number of queries.
Each of the next q lines describes a query from Polycarp:
The j-th line, at first, contains the integer tj (1≤tj≤3) — the type of query.
If the query is of type tj=1 or tj=2 then the integer kj (1≤kj≤n) — the length of the shift — follows in the same line.
Output
Output q+1 numbers — the minimum number of carriage resets required before and after each of Polycarp's queries.
Examples
input
3 2 3 1 0
output
1
input
3 1 2 3 2 2 1 3
output
0 2 1
input
5 3 1 2 5 4 5 1 3 3 2 3 1 4 3
output
3 2 1 2 1 2
题意:
给你一个序列,执行若干次 整体左移/整体右移/翻转 操作,问当前序列需要多少次操作变成一个递增序列
每次操作:将一个数往前移动任意位 并 可以选择任意个数往后移动
思路:
序列总共有2*n种情况,全部预处理出来,维护序列的状态即可
对于初始状态下的序列,每一个 p[i]<i 的位置都需要往前移动,统计答案即可
由于1e5的数据不能暴力统计所有状态的次数,需要优化,用 ans[i] 记录初始序列右移 i 位后序列需要移动的次数,用 c [i] 记录 原序列 p[k]-k=i 的位置个数,这些位置原本可以顺带往后移动到目标位置,但是 在右移 i+1 次的序列后,这些位置处于目标位置的下一位,贡献一个答案
同时我们发现,每一次右移序列,都会把最后一位放到最前面,使得答案减一,原来需要前移,现在不用前移,所以每次右移时,加上会错位的个数再减一即可
代码:
#include<bits/stdc++.h>
#define endl '\n'
#define debug(x) cout<<#x<<'='<<x<<endl;
using namespace std;
#define int long long
typedef pair<int,int> pii;
typedef long long ll;
const int INF=0x3f3f3f3f;
void solve(){
int n;
cin>>n;
vector<int>p(n);
for(int i=0;i<n;i++){
cin>>p[i]; //初始序列
p[i]--;
}
vector<int>ans[2]; //翻转前后
auto deal=[&](){
vector<int>ans(n,0),c(n,0);
for(int i=0;i<n;i++){
ans[0]+=(p[i]<i); //统计初始答案
c[(p[i]-i+n)%n]++; //记录c[k],错位k的个数
}
for(int i=1;i<n;i++){
ans[i]=ans[i-1]+c[i-1]-1; //加上正好错开的个数,减去最后一个减少的共线
}
return ans;
};
ans[0]=deal();
reverse(p.begin(),p.end());
ans[1]=deal();
int q;
cin>>q;
cout<<ans[0][0]<<endl;
int flag=0,cnt=0; //维护序列状态
while(q--){
int op;
cin>>op;
if(op==1){
int x;
cin>>x;
cnt=(cnt-x+n)%n;
}
if(op==2){
int x;
cin>>x;
cnt=(cnt+x)%n;
}
if(op==3){
flag^=1;
cnt=(n-cnt+n)%n;
}
cout<<ans[flag][cnt]<<endl;
}
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
//cin>>T;
while(T--){
solve();
}
return 0;
}