codeforces 1300分

文章目录

  • 1.[B. Random Teams](https://codeforces.com/contest/478/problem/B)
  • 2.[D. Anti-Sudoku](https://codeforces.com/problemset/problem/1335/D)
  • 3.[B. Trouble Sort](https://codeforces.com/problemset/problem/1365/B)
  • 4.[Problem - 1401C - Codeforces](https://codeforces.com/problemset/problem/1401/C)
  • 5.[Problem - 1367C - Codeforces](https://codeforces.com/problemset/problem/1367/C)
  • 6.[C. Coin Rows](https://codeforces.com/problemset/problem/1555/C)
  • 7.[B. Nastia and a Good Array](https://codeforces.com/problemset/problem/1521/B)
  • 8.[A1. Prefix Flip (Easy Version)](https://codeforces.com/problemset/problem/1381/A1)
  • 9.[D. Number into Sequence](https://codeforces.com/problemset/problem/1454/D)
  • 10.[C1. Pokémon Army (easy version)](https://codeforces.com/contest/1420/problem/C1)
  • 11.[C. Closest Cities](https://codeforces.com/contest/1922/problem/C)
  • 12.[B. Road Construction](https://codeforces.com/problemset/problem/330/B)
  • 13.[A. Di-visible Confusion](https://codeforces.com/contest/1603/problem/A)
  • 14.[C. Matching Numbers](https://codeforces.com/problemset/problem/1788/C)
  • 15.[D. Co-growing Sequence](https://codeforces.com/problemset/problem/1547/D)
  • 16.[B. Simple Game](https://codeforces.com/problemset/problem/570/B)
  • 17.[B. Swap and Delete](https://codeforces.com/contest/1913/problem/B)
  • 18.[C. Game with Multiset](https://codeforces.com/contest/1913/problem/C)
  • 19.[D. Ice Cream Balls](https://codeforces.com/problemset/problem/1862/D)
  • 20.[A. Knapsack](https://codeforces.com/problemset/problem/1446/A)
  • 21.[C. Parity Shuffle Sorting](https://codeforces.com/problemset/problem/1733/C)
  • 22.[A1. Make Nonzero Sum (easy version)](https://codeforces.com/problemset/problem/1753/A1)
  • 23.[C. Elemental Decompress](https://codeforces.com/problemset/problem/1768/C)
  • 24.[D. Twist the Permutation](https://codeforces.com/problemset/problem/1650/D)
  • 25.[D. Twist the Permutation](https://codeforces.com/problemset/problem/1650/D)
  • 26.[C. Divisor Chain](https://codeforces.com/contest/1864/problem/C)
  • 27.[C. Permutation Operations](https://codeforces.com/problemset/problem/1746/C)
  • 28.[C. Ehab and a Special Coloring Problem](https://codeforces.com/problemset/problem/1174/C)
  • 29.[B. Gardener and the Array](https://codeforces.com/problemset/problem/1775/B)
  • 30.[C. Ice and Fire](https://codeforces.com/problemset/problem/1774/C)
  • 31.[A. Qingshan Loves Strings 2](https://codeforces.com/contest/1889/problem/A)
  • 32.[B. New Year's Eve](https://codeforces.com/problemset/problem/912/B)
  • 33.[C. Insert Zero and Invert Prefix](https://codeforces.com/contest/1839/problem/C)
  • 34.[B. Binary String Constructing](https://codeforces.com/problemset/problem/1003/B)
  • 35.[A. Packets](https://codeforces.com/problemset/problem/1037/A)
  • 36.[C. Insert and Equalize](https://codeforces.com/problemset/problem/1902/C)
  • 37.[B. Vasya and Isolated Vertices](https://codeforces.com/problemset/problem/1065/B)
  • 38.[A. Fill in the Matrix](https://codeforces.com/problemset/problem/1868/A)
  • 39.[B. Bit Flipping](https://codeforces.com/problemset/problem/1659/B)
  • 40.[A. Oh Those Palindromes](https://codeforces.com/problemset/problem/1063/A)
  • 41.[C. Salyg1n and the MEX Game](https://codeforces.com/problemset/problem/1867/C)
  • 42.[C. Labs](https://codeforces.com/problemset/problem/1236/C)
  • 43.[B. Painting Pebbles](https://codeforces.com/problemset/problem/509/B)
  • 44.[B. Sonya and Exhibition](https://codeforces.com/problemset/problem/1004/B)
  • 45.[A. Difference Row](https://codeforces.com/problemset/problem/347/A)
  • 46.[B. Neko Performs Cat Furrier Transform](https://codeforces.com/problemset/problem/1152/B)
  • 47.[C. Dividing the numbers](https://codeforces.com/problemset/problem/899/C)
  • 48.[A. Lucky Permutation Triple](https://codeforces.com/problemset/problem/303/A)
  • 49.[B. Students in Railway Carriage](https://codeforces.com/problemset/problem/962/B)
  • 50.[B. Vika and Squares](https://codeforces.com/problemset/problem/610/B)

1.B. Random Teams

n个人,分成m组,每个组至少分一个人

靠一些直觉,分别对最大和最小进行思考
最大:除一组外其它全为1
最小:平均分,那么怎样平均分呢?

trick:平均分的做法:先每组分配n/m,如果n%m不为0的话,那么取n%m个加1

主要是对平均分这一技巧的掌握

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n,m;
void solve() {cin>>n>>m;int t=n-m+1;int maxn=t*(t-1)/2;int x=n/m;int y=n%m;int minn=(x+1)*x/2*y+x*(x-1)/2*(m-y);cout<<minn<<' '<<maxn<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

2.D. Anti-Sudoku

9 * 9的数独,最多改掉9个数,使得每行,每列,每个3 * 3都至少有两个相同的元素(题目说一定有解)

直觉是修改的数值每行每列都不一样,比如(1,1),(2,2),…(9,9)通过样例来验证,是适用的
那么具体改成什么值呢?由于原本这是一个数独,即每行1到9不重复,没列1到9不重复,3 * 3中1到9不重复,所以只要改成不一样的就会造成它所在行,列,3 * 3会出现至少两个相同的元素,发现这样不行,还得再改改,这样的话很多3 * 3还是没有改掉,所以还要考虑3 * 3

trick:直接对以下进行修改
(1,1) (2,4)(3,7)
(4,2) (5,5)(6,8)
(7,3) (8,6)(9,9)

当然,这里也有一定的技巧,就是横纵坐标分别放到dx数组和dy数组里,直接遍历即可,而不是写9个if

#include<bits/stdc++.h>
#define endl '\n'
//#define int long long
using namespace std;
char a[10][10];
int dx[9]={1,2,3,4,5,6,7,8,9};
int dy[9]={1,4,7,2,5,8,3,6,9};
void solve() {for(int i=1;i<=9;i++){for(int j=1;j<=9;j++){cin>>a[i][j];}}for(int i=0;i<9;i++){int x=dx[i],y=dy[i];if(a[x][y]=='9') a[x][y]='1';else a[x][y]=(char)(a[x][y]+1);}for(int i=1;i<=9;i++){for(int j=1;j<=9;j++){cout<<a[i][j];}cout<<endl;}
}
int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

3.B. Trouble Sort

n个整数
ai表示值,bi表示类型
操作:选择两个类型不同的数,交换它们
操作不限次数,使得非降序,问是否可以

只要分别将两种类型的升序,然后合并在一起,再检验是否非降序
难点在于怎么实现:其实很简单,就是先把两种类型的数分别放在不同的multiset里,然后依次按照类型赋值回去即可
由于multiset中的erase是删掉的是与之相同的所有元素,我要删第一个,不知道怎么删,所以改成小根堆

样例一直错,然后才发现题目读错了,全都白分析了,不对,题目读对了,但是在分析的时候错乱了,刚好把题意记反了,记成交换相同类型的了

这告诉我们一个道理:先别急着敲代码,先看看想出的方法是不是对样例适用,应该至少保证样例全都适用

后面想的是进行一个类似于冒泡排序,就是如果类型不同且大小逆序就互换,但是时间复杂度肯定不允许

trick:操作是对某个数进行交换且操作次数不限,那么看两两交换是否可以扩展到更多数的交换,这里只要有0和1的交错,那么就全部都可以随意交换

#include<bits/stdc++.h>
#define endl '\n'
//#define int long long
using namespace std;
const int N=1e5+10;
int a[N],b[N];
int n;
void solve() {cin>>n;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++) cin>>b[i];bool flag=true;int cnt_0=0,cnt_1=0;if(b[1]==0) cnt_0++;else cnt_1++;for(int i=2;i<=n;i++){if(a[i-1]>a[i]) flag=false;if(b[i]==0) cnt_0++;else cnt_1++;}if(flag){cout<<"Yes"<<endl;return;}if(cnt_0==0||cnt_1==0) cout<<"No"<<endl;else cout<<"Yes"<<endl;
}
int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

4.Problem - 1401C - Codeforces

长度为n的数组

ai为正整数

操作:选择两个数,如果它们的最大公因数等于整个数组最小的那个就可以交换
操作次数不限

要求使a非降序

想想是否可以扩展一下交换
数组中最小的数在数组给定之后就已经确定下来了

至此都没什么解题的突破口

trick:

这类题都是有一般套路的

这类题的特征:操作是满足某性质的两个数可以交换,操作次数不限,目标是排好序

思考方向为是否有中间量可以作为交换的媒介,两数通过中间的媒介进行交换,某个数如果和中间量有联系的话,那么就可以和其它任意和中间量有联系的进行交换,从而达到自由移动

另外一种思考的方向是,我们要的结果是确定的,所以先排个序,结果确定下来,然后看位置不正确的数是否全部都可以自由移动

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=1e5+10;
int a[N],b[N];
int n;
int gcd(int a,int b){if(b==0) return a;return gcd(b,a%b);
}
void solve() {cin>>n;int minn=2e9;for(int i=1;i<=n;i++) cin>>a[i],b[i]=a[i],minn=min(minn,a[i]);sort(b+1,b+1+n);for(int i=1;i<=n;i++){if(a[i]!=b[i]){if(gcd(a[i],minn)!=minn){cout<<"No"<<endl;return;}}}cout<<"Yes"<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

5.Problem - 1367C - Codeforces

1到n张桌子
长度为n的01字符串,1代表餐桌有人,0代表没人
保证给定字符串中任意两个1相差距离大于k
然后问最多将几个0变成1使得任意两个1相差距离仍然大于k

如果当前字符为0的话,查找往后k个距离内是否有1,如果没有就可以将该位置的0变为1,并跳到i+k的位置

如果当前字符为1的话,那么直接跳到i+k的位置

trick:

当出现最的时候,一种思路就是贪心:最好是怎么样,实在没办法才舍弃

贪心其中一种方向就是从前往后遍历,一边遍历一边贪,若可以将该位置的0变成1则变,尽可能多

#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N = 2e5 + 10;
int a[N];
int n, k;
string s;
void solve() {cin >> n >> k;cin >> s;vector<int>pos;//存放1的位置for (int i = 0; i < n; i++) {if (s[i] == '1') pos.push_back(i);}int ans = 0;for (int i = 0; i < (int)s.size(); i++) {if (s[i] == '0') {int pos1 = upper_bound(pos.begin(), pos.end(), i) - pos.begin();if (pos1 >= 0 && pos1 < (int)pos.size()) {if(pos[pos1] - i > k){ans++;i = i + k;}}else{ans++;i=i+k;}} else {i = i + k;}}cout << ans << endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t = 1;cin >> t;while (t--) {solve();}return 0;
}

6.C. Coin Rows

矩阵
共m列,2行
aij表示硬币数量

博弈
起点为(1,1),终点为(2,m)
操作:往右移动一格或者往下移动一格

最终分数为Bob获取的硬币数量
Alice从起点走到终点,拿取硬币
Alice想使得分数最小
Bob再走,想使分数最大

两者独立,互不相关

有关于数学数字,归结为数学敏感,手玩,找规律

0c6358664849d7041ff52f6808dd4bd5

trick:

1.有关于数学数字,归结为数学敏感,手玩,找规律

2.不要乱加特判,情况虽然简单,但不要也开始就加上,先看一般情况能否覆盖特殊情况,如果可以覆盖,那么它就不是特殊情况,加了特判反而容易错

这边对m=2时特判反而错了,属于画蛇添足了

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=1e5+10;
int a[3][N];
int last[N],pre[N];
int m;
void solve() {cin>>m;for(int i=1;i<=2;i++){for(int j=1;j<=m;j++){cin>>a[i][j];}}//特判if(m==1){cout<<0<<endl;return;}//预处理第一行的后缀和last[m]=a[1][m];for(int i=m-1;i>=1;i--) last[i]=last[i+1]+a[1][i];//预处理第二行的前缀和pre[1]=a[2][1];for(int i=2;i<=m;i++) pre[i]=pre[i-1]+a[2][i];//遍历int ans=2e9;ans=min(ans,pre[m-1]);ans=min(ans,last[2]);for(int i=1;i<=m-2;i++){//i为第二行前缀的长度int len=m-i-1;//第一行后缀的长度ans=min(ans,max(pre[i],last[m+1-len]));}cout<<ans<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

7.B. Nastia and a Good Array

长度为n的数组a,均为正整数

good数组:所有相邻两个数最大公因数均为1
操作:选择任意两个数,将其中一个数变成小的那个数min,另一个数随便变成一个大于等于min的数
最多操作n次,可以证明一定可以实现,变成good数组
输出操作

有一个很重要的性质:相差为1的两个数的最大公因数肯定为1,这在之前做题的时候做到过
把相邻的两个数变成相差为1的两个数,n次绝对够了,而且是刚好n-1次,想错了,没有想到修改后面就把前面的数给改了
为了避免修改前面的数会把后面的数给改掉,需要按升序的顺序来,这样ok了,这样还是不对,因为虽然排序了,但是原本的顺序是没有打乱的
而升序还有一个原因----该题与顺序无关,先排个序

这题最小的数可以保留,然后其它都可以变成大于等于最小数的任何数,那么可以奇数位全放最小数,偶数位全放最小数+1,或者偶数位全放最小数,奇数位全放最小数+1

trick:

1.相差为1的两个数的最大公因数肯定为1,这是之前做题做到过的,一个很重要很关键的性质,但是这里还要再拓展一下,题目要求是任意相邻两个数的最大公因数均为1,可能会想到每次都加1,呈现一个升序的状态,但是也可以减1,加1,这样就分为奇数位和偶数位,奇数位均相同,偶数位均相同,奇数位上的数和偶数位上的数差1

2.将一个数和另一个数联系起来,输出的时候输出这两个数,包括上次做到的输出生成树一条边的两个端点,看是否可以其中一个数就固定下来

3。挖掘操作(动作)的性质,想想哪些是一定的,首先做什么是一定的,在这里是最小的那个数一定是可以保留的

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=1e5+10;
int a[N];
int n;
void solve() {cin>>n;for(int i=1;i<=n;i++) cin>>a[i];int pos=1,minn=a[1];for(int i=2;i<=n;i++){if(a[i]<minn){minn=a[i];pos=i;}}cout<<n-1<<endl;if(pos%2==1){for(int i=1;i<=n;i++){if(pos==i) continue;if(i%2==0) cout<<pos<<' '<<i<<' '<<a[pos]<<' '<<a[pos]+1<<endl;else cout<<pos<<' '<<i<<' '<<a[pos]<<' '<<a[pos]<<endl;}}else{for(int i=1;i<=n;i++){if(pos==i) continue;if(i%2==0) cout<<pos<<' '<<i<<' '<<a[pos]<<' '<<a[pos]<<endl;else cout<<pos<<' '<<i<<' '<<a[pos]<<' '<<a[pos]+1<<endl;}}
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

8.A1. Prefix Flip (Easy Version)

长度为n的数组a和数组b,01串
操作:取长度为len的前缀,将0变成1,将1变成0,然后翻转
将字符串a变成b,需操作几次(最多3*n次,一定有解)

3次操作:翻转前i个字符,翻转第1个字符,再翻转前i个字符,可以将第i个字符进行翻转–这个规律真的很难发现,通过手玩也很难,可以记一下这个规律

trick:

1.一定有解,最多3*n次–>肯定可以构造出一种万能的通用的解,因为最多n个字符,然后通过3可以猜测每3次就可以将一个字符翻转

2.非常通用的一种方法–手玩

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n;
string a,b;
void solve() {cin>>n;cin>>a>>b;vector<int>ans;for(int i=0;i<n;i++){if(a[i]!=b[i]){ans.push_back(i+1);ans.push_back(1);ans.push_back(i+1);}}cout<<ans.size()<<' ';for(auto v:ans) cout<<v<<' ';cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

9.D. Number into Sequence

构造序列,每个数大于1,所有数乘积为n,后一个数是前一个数的倍数,长度要最大(一定有解)

分解质因数,将出现次数最多的质因数(假设k个)输出k-1个,剩下一个和其它乘积

trick:

数学知识:每个合数都可以写成几个质数相乘的形式(唯一),其中每个质数都是这个合数的因数,把一个合数用质因数相乘的形式表示出来,叫做分解质因数,这样得到的分解因数的序列一定是最长的,因为质数不能再分解了,然后将质因数乘积合成一个因数,这样可以有办法满足题意得最长序列

分解质因数的模板:试除法

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n;
void solve() {cin>>n;int m=n;vector<int>ans;map<int,int>mp;for(int i=2;i<=n/i;i++){if(n%i==0){ans.push_back(i);while(n%i==0) {n/=i;mp[i]++;}}}if(n>1){ans.push_back(n);mp[n]++;}
//	for(int i=0;i<(int)ans.size();i++) cout<<ans[i]<<' '<<mp[ans[i]]<<endl;int maxn=mp[ans[0]];int maxi=ans[0];for(int i=1;i<(int)ans.size();i++){if(maxn<mp[ans[i]]){maxn=mp[ans[i]];maxi=ans[i];}}cout<<maxn<<endl;for(int i=0;i<maxn-1;i++) cout<<maxi<<' ';cout<<m/(int)pow(maxi,maxn-1)<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

10.C1. Pokémon Army (easy version)

n个神奇宝贝
ai表示神奇宝贝的实力(均不同)

按顺序挑选神奇宝贝,加减交替,得到该支军队的实力,求出最大兵力

开头和结尾肯定是要加的(让个数为奇数,不然后面减一个肯定变小)
通过手玩造样例发现,比如8 7 6 5 4,如果选择8,7,6,5,10,那么最终结果是8-7+6-5+10=12,而选择8,5,10,则为8-5+10=13,所以一加一减选择一个最大的和最小的,它其实就是一个波峰波谷,每次都选择波峰和波谷即可

trick:
1.手玩–造样例

2.找波峰和波谷

波峰:a[i] > a[i - 1] && a[i] > a[i + 1]

波谷:a[i] < a[i - 1] && a[i] < a[i + 1]

#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N = 3e5 + 10;
int a[N];
int n, q;
void solve() {cin >> n >> q;for (int i = 1; i <= n; i++) cin >> a[i];//找波峰和波谷bool flag = 1; //1表示要找波峰,0表示要找波谷vector<int>ans;if (a[1] > a[2]) ans.push_back(a[1]), flag = 0;for (int i = 2; i <= n - 1; i++) {if (flag == 1) { //找波峰if (a[i] > a[i - 1] && a[i] > a[i + 1]) ans.push_back(a[i]), flag = 0;} else if (flag == 0) { //找波谷if (a[i] < a[i - 1] && a[i] < a[i + 1]) ans.push_back(a[i]), flag = 1;}}if (a[n] > a[n - 1]) ans.push_back(a[n]);int res = 0;for (int i = 0; i < (int)ans.size() - 1; i += 2) {res += ans[i] - ans[i + 1];}res += ans[ans.size() - 1];cout<<res<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t = 1;cin >> t;while (t--) {solve();}return 0;
}

11.C. Closest Cities

长度为n的数组a,数的范围为[0,1e9]
共m行询问,每次给定两个整数x和y,计算从城市x到城市y需要花费最少的硬币数
共m座城市,位于ai,按升序排列
对于一座城市,离它最近的城市是唯一的

操作:从城市x到y,花费它们距离的金币或者到离x最近的城市(唯一的)花费1金币

x和y在两个方向,x朝着y方向走,一直走最近,直到最近的是往回走,千万不能走回头路,此时直接花费距离金币到y
并查集不可行,并查集不能有环,那就用两个并查集,往右的和往左的,但是这样是错的,因为并不是走到并查集的头就断了,可以先利用城市距离过去再继续走最近城市

由于不能走回头路,所以我们利用一个前缀和以及后缀和就可以了,如果可以走最近城市那么就加1,否则就加两城市之间的距离
不能走回头路,然后如果能走最近城市就走最近城市,如果不能走就花费距离金币,这样花费代价是最小的

trick:

1.多次询问区间以及不能走回头路,考虑方向为前缀和

2.并查集是不能出现环的

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=1e5+10;
int a[N];
int pre[N],last[N];
int n,m;
void solve() {cin>>n;memset(pre,0,sizeof pre);memset(last,0,sizeof last);for(int i=1;i<=n;i++) cin>>a[i];//前缀和for(int i=1;i<n;i++){if(i==1) pre[i+1]=pre[i]+1;else{if(abs(a[i]-a[i+1])<abs(a[i]-a[i-1])) pre[i+1]=pre[i]+1;else pre[i+1]=pre[i]+abs(a[i]-a[i+1]);}}//后缀和for(int i=n;i>1;i--){if(i==n) last[i-1]=last[i]+1;else{if(abs(a[i]-a[i-1])<abs(a[i]-a[i+1])) last[i-1]=last[i]+1;else last[i-1]=last[i]+abs(a[i]-a[i-1]);}}cin>>m;while(m--){int x,y;cin>>x>>y;if(x<y) cout<<pre[y]-pre[x]<<endl;else cout<<last[y]-last[x]<<endl;}
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

12.B. Road Construction

一共有n座城市
建设道路(无向图),对于一座城市,到任何其它城市最多穿越两条道路
m对城市不能建设道路
一定有解
输出最少建设多少条道路,输出具体建设情况

记录不能建设道路的情况,记录每个城市不能用到的次数,次数最少的x去匹配那些可以和它连的,对于不能和x连的,看是否可以连到x的一级分支上
数据比较小,可以选择暴力

trick:

1.当两者需要联系起来时输出,往往其中一个可以定死,这是之前总结过的,在这里是解题的关键

2.数据比较小,直接暴力

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=1010;
int n,m;
bool st[N][N];
void solve() {cin>>n>>m;map<int,int>mp;memset(st,false,sizeof st);for(int i=0;i<m;i++){int x,y;cin>>x>>y;st[x][y]=st[y][x]=true;mp[x]++;mp[y]++;}int minn=2e9,mini=-1;for(int i=1;i<=n;i++){if(minn>mp[i]){minn=mp[i];mini=i;}}cout<<n-1<<endl;vector<int>ans;vector<int>res;for(int i=1;i<=n;i++){if(i==mini) continue;if(!st[mini][i]) cout<<mini<<' '<<i<<endl,res.push_back(i);else ans.push_back(i);}for(int i=0;i<(int)ans.size();i++){//枚举和mini不能相连的for(int j=0;j<(int)res.size();j++){if(!st[ans[i]][ans[j]]) cout<<ans[i]<<' '<<ans[j]<<endl;}}
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

13.A. Di-visible Confusion

长度为n的数组a(数的范围[1,1e9])
操作:选择一个索引i,保证ai不是i+1的倍数,删掉ai
直到序列为空、
问是否可以删除整个序列

手玩
要想删掉第一个数,那么第一个数就不能是2的倍数(第一个数要看的索引是固定的,是2)
如果全部是奇数,那么就一直删第一个数
删掉后面不会影响前面,删掉前面会影响后面
先把能删的都删掉,然后剩下的就都是不能删的了
然后只要把第一个删掉,所有都错一位,这样全部都变成能删的了,然后从后往前一个一个删
综上所述,如果第一个数是奇数的话, 那么Yes,否则N
全错了,这样错位下来不一定,比如说30,既是5的倍数,又是6的倍数

该题的做法是假设第i个数前面的数都可以被删掉,那么第i个数只要在2到i+1中有一个不是因数,也可以被删掉,如果有一个数,2到i+1全部都是它的因数的话,那么它不可能被删掉

由于2乘以3,一直乘到大概23就超过1e9了,所以最多判断22个数,这样双重循环是不会超时的

trick:

1.整除想到因子

2.对于删数问题,肯定是一位一位删,不可能一下子全部都删掉,其中一个思考的方向是假设前面的数全部都可以删掉,然后如何删掉该数

3.如果x是很多数的倍数,那么x也是它们最小公倍数的倍数,判断x是否是很多数的倍数,只需看是否是它们最小公倍数的倍数,一个一个判断是否是因子,那么阶乘级别的,判断次数不会很多,就会有一个不是因子

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=1e5+10;
int a[N];
int n;
void solve() {cin>>n;for(int i=1;i<=n;i++) cin>>a[i];bool flag=true;for(int i=1;i<=n;i++){bool ok=false;for(int j=i+1;j>=2;j--){if(a[i]%j!=0){ok=true;break;}}flag&=ok;}if(flag) cout<<"Yes"<<endl;else cout<<"No"<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

14.C. Matching Numbers

给定n
然后让1到2*n两两匹配,使得它们的和按顺序分别是加1

它们所有的和是固定的,然后每个数都差1,求和就是等差数列,等差数列一共n个数

可以列出一个式子,假设第一个和为x,那么(x+x+n-1) * n /2=(1+2 * n)* 2 * n /2

得到x=(3 * n+3)/2

然后n个和即为,x,x+1,…x+n-1

通过手玩发现构造规律:将1到2n分成两半,左半边的x-(n+1)到n分别按次序和右半边相加,然后右半边剩下的按次序和左半半剩下的相加即可

trick:

突破口在于和是固定的,一旦找到某个是不变的,它就是题目的突破口

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n;
void solve() {cin>>n;if((3*n+3)%2){cout<<"No"<<endl;return;}int x=(3*n+3)/2;//第一个和int pos=x-(n+1);cout<<"Yes"<<endl;int idx;for(int i=n+1,j=pos;j<=n;i++,j++){cout<<i<<' '<<j<<endl;idx=i;}for(int i=idx+1,j=1;i<=2*n;i++,j++){cout<<i<<' '<<j<<endl;}
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

15.D. Co-growing Sequence

长度为n的数组x(数的范围[0,1e9])
增长序列:任意i,ai & ai+1 =ai(n为1也是增长序列)

构造序列b,ai^bi=ci,使得c是增长序列(这里ai并不是增长序列)
求b的字典序最小

b 1 b_1 b1可以任意,直接取为最小,为0

即( a i a_i ai$b_i$)&($a_{i+1}$ b i + 1 b_{i+1} bi+1)= a i + 1 a_{i+1} ai+1^ b i + 1 b_{i+1} bi+1

得到 a i a_i ai$b_i$中1所在的位,$a_{i+1}$ b i + 1 b_{i+1} bi+1也都是1,由于 a i + 1 a_{i+1} ai+1已知,那么只需要把 a i + 1 a_{i+1} ai+1中应该为1的位但不是1的改成1即可作为b,其它位都为0,这样必要的1有了,其它都为0,字典序最小

trick:

1.按位异或,一个重要的性质是,相同为0,即aa=0,从而得到abb=a,即a=abb,如果题目要求构造一个数使得该数和给定数a异或起来满足要求,可以先把满足要求的数x确定下来,然后需要构造的数y=xa(因为ay=x,所以aya=xa)

如果两者异或起来为1的话,那么两者不同,由于二进制只有0和1,所以两者其中一个是0,另一个是1,换句话说,两者刚好相反,互补

2.按位与,如果a & b =a,那么a中1所在的位,b也都是1

3.按位或,如果a中为1的位,b都想要为1,同时保留b中原有的1,那么b或上a,相当于将两者为1的位都并起来为x,如果p^q为x的话,除了两者都为0的位,其它位都互补

# include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=2e5+10;
int a[N],b[N];
int n;
void solve() {cin>>n;for(int i=1;i<=n;i++) cin>>a[i];b[1]=0;for(int i=2;i<=n;i++){int x=a[i-1]^b[i-1];b[i]=(x|a[i])^a[i];///a[i]^b[i]=x|a[i]}for(int i=1;i<=n;i++) cout<<b[i]<<' ';cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

16.B. Simple Game

在1到n中选择一个数
两个人M和A博弈,对于随机整数c,谁选的数离c近,谁就赢,如果距离相同,M赢

M数字已知,要想让A赢的概率最大,A应该选择哪个数

根据样例,看M在左半边还是右半边
选择数字M-1或者M+1
M-1和n-(M+1)+1=n-M比,哪个大选哪个

坑点:

M-1和M+1超出选数的范围了

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n,m;
void solve() {cin>>n>>m;if(m-1>=n-m&&m-1>=1) cout<<m-1<<endl;else if(m-1<n-m&&m+1<=n) cout<<m+1<<endl;else cout<<m<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

17.B. Swap and Delete

1000分的题,但还是归到这来,因为这题和之前做过的题联系起来了,比较有重大意义

给定一个01串s
操作:删除一个字符,花费1金币或者免费交换一对字符
次数不限

使得ti不等于si对于整个t(可以为空)
问最少花费多少金币

两个一样的序列进行0和1的匹配,分别统计0和1的数量,从头开始遍历,一直到不能匹配

trick:

1.两两可以任意交换–可以随便排序

2.两两匹配问题

分为三种

第一种是序列内部进行两两匹配,比如说最小和最大匹配,次小和次大匹配

第二种是两个不同的序列进行匹配,比如说每次匹配差值最大的,要么序列a的最大和序列b的最小匹配,要么序列a的最小和序列b的最大匹配

第三种是两个一样的序列进行匹配,一般是通过自身元素的两两交换来满足某个要求,本质上就是自身和自身匹配

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
string s;
void solve() {cin>>s;int n=s.size();map<char,int>mp;for(int i=0;i<n;i++) mp[s[i]]++;for(int i=0;i<(int)s.size();i++){if(s[i]=='1'){if(mp['0']) mp['0']--;else{cout<<n-i<<endl;return;}}else{if(mp['1']) mp['1']--;else{cout<<n-i<<endl;return;}}}cout<<0<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

18.C. Game with Multiset

add x表示在集合中添加一个2的x次方
get w问是否可以从集合中取得一些数,和为w

trick:
任何一个数都可以由若干个2的次幂组成

有两种方法:

1.将该数转化成二进制,然后一位一位看,如果第x位为1的话,那么 就有 2 x 2^x 2x,具体操作方法可以参考快速幂

int cnt=0;
while(x){
if(x&1) ans.push_back(cnt); 
x>>=1;
cnt++;
}

2.从高到低贪心

for(int i=29;i>=0;i--){
if(x>=(1ll<<i)){ans.push_back(i);x-=(1ll<<i);
}
}

但是你会发现,每一位二进制数都只用一次,该题中每个2的次幂不止一个,实际上从大到小贪心和每个2的次幂只用一次的贪心本质上是一样的

如果某个2的次幂有多个的话,那么就只保留一个(有奇数个)或者 一个也不保留(有偶数个),然后其余的进行合成,往上进位

比如说有5个 2 3 2^3 23,想当于1个 2 5 2^5 25

再比如说6个 2 3 2^3 23,相当于1个 2 5 2^5 25以及1个 2 4 2^4 24

所以总能转化成每个2的次幂只用一次

所以从高到低进行贪心,如果能构成就能,不能就不能

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int m;
void solve() {cin>>m;map<int,int>mp;while(m--){int op,x;cin>>op>>x;if(op==1) mp[x]++;else{for(int i=29;i>=0;i--){if(mp[i]){x-=min(x/(1ll<<i),mp[i])*(1ll<<i);}}if(x==0) cout<<"YES"<<endl;else cout<<"NO"<<endl;}}
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

19.D. Ice Cream Balls

n表示想要制作多少种类型的冰淇淋(exactly)
两个球做成一个冰淇淋
问最少需要买几个球(答案总是存在)

之前做过了

二分求出C(x,2)小于等于n,x为不同类型球的数量,然后剩下的补足买之前已经买过的

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n;
int C2(int x){return x*(x-1)/2;
}
void solve() {cin>>n;int l=1,r=1e10;while(l<r){int mid=(l+r+1)/2;if(C2(mid)>n) r=mid-1;else l=mid;}if(C2(l)==n) cout<<l<<endl;else cout<<l+n-C2(l)<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

20.A. Knapsack

共n个物品,权重为wi
背包容量为W

其实审题这一步很关键,最有用的办法就是一边读题一边用自己的话记录,一边理解一边想

将物品放入背包,使得重量大于等于背包容量的一半,输出一种方案,无解输出-1

发现贪心可行
从大往小贪,只要可以放就放,一旦超过了总容量的一半就可以结束了,如果直到最后都没有超过总容量的一半,就无解
证明:从大到小遍历,首先如果第一个就超过总容量的一半,那么直接结束,否则,就看下一个,由于大的都没有超过总容量的一半,再加一个小的一定不会超过总容量,假设加起来超过总容量的一半,那么直接结束,否则同理,再往下加也不会超过总容量的

trick:

1.其实审题这一步很关键,最有用的办法就是一边读题一边用自己的话记录,一边理解一边想

2.当脑子里立马蹦出个思路,特别是贪心,一定要造不同情况的复杂的极端的样例进行验证

3.如果排序后仍需要知道下标,可以将pair类型存入vector,这比结构体方便

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
typedef pair<int,int>PII;
int n,w;
void solve() {cin>>n>>w;vector<PII>ans;for(int i=1;i<=n;i++){int x;cin>>x;ans.push_back({x,i});}sort(ans.begin(),ans.end());reverse(ans.begin(),ans.end());int sum=0;vector<int>res;for(int i=0;i<(int)ans.size();i++){if(w>=ans[i].first){sum+=ans[i].first;res.push_back(ans[i].second);if(sum>=(w+1)/2){cout<<res.size()<<endl;for(auto v:res) cout<<v<<' ';cout<<endl;return;}}}cout<<-1<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

21.C. Parity Shuffle Sorting

长度为n的数组a(数[0,1e9])
操作:选择两个数,如果两个数的和为奇数,那么让后一个数等于前一个数,如果和为偶数,那么让前一个数等于后一个数
最多n次–>尽可能都用完
使序列非降序,一定有解–>万能通用的方法

操作的对象为两个,可以让一个定死,也可以让两个都定死
有一个不变的点就是里面的数不能凭空出现里面没出现过的数
如果第一个数是偶数的话,那么先让所有偶数都变相同,然后所有的奇数都变得和第一个数一样
如果第一个数是奇数的话,同理

trick:

1.操作的对象为两个,可以让一个定死,也可以让两个都定死

2.有关数学(奇偶数,质数,合数,因数,只要是关于数的)以及构造的,都往奇偶分位以及奇数偶数方向分类想

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
typedef pair<int,int>PII;
const int N=1e5+10;
int a[N];
int n;
void solve() {cin>>n;for(int i=1;i<=n;i++) cin>>a[i];vector<PII>ans;if(a[1]%2==0){int idx=-1;for(int i=n;i>=1;i--){if(a[i]%2==0){idx=i;break;}}if(idx!=1){for(int i=1;i<=n;i++){if(i==idx) break;if(a[i]%2==0) ans.push_back({i,idx});}}for(int i=2;i<=n;i++){if(a[i]%2) ans.push_back({1,i});}}else{int idx=-1;for(int i=n;i>=1;i--){if(a[i]%2){idx=i;break;}}if(idx!=1){for(int i=1;i<=n;i++){if(i==idx) break;if(a[i]%2) ans.push_back({i,idx});}}for(int i=2;i<=n;i++){if(a[i]%2==0) ans.push_back({1,i});}}cout<<ans.size()<<endl;for(auto v:ans) cout<<v.first<<' '<<v.second<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

22.A1. Make Nonzero Sum (easy version)

长度为n的数组a(均为正负1)

分段,每个分段的计数方法为加减交替,第一个数为加
满足所有分段加起来为0

如果n为奇数,无解
n为偶数,一定有解,前后两个要么一样,要么不一样,如果一样的话,就放在一段,如果不一样,就分别一段

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
typedef pair<int,int>PII;
const int N=2e5+10;
int a[N];
int n;
void solve() {cin>>n;for(int i=1;i<=n;i++) cin>>a[i];if(n%2==1){cout<<-1<<endl;return;}vector<PII>ans;for(int i=1;i<=n;i+=2){if(a[i]==a[i+1]) ans.push_back({i,i+1});else ans.push_back({i,i}),ans.push_back({i+1,i+1});}cout<<ans.size()<<endl;for(auto v:ans) cout<<v.first<<' '<<v.second<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

23.C. Elemental Decompress

长度为n的数组a(数[1,2e5])

构造两个全排列,使得max(pi,qi)=ai,可能无解

ai并不是全排列
ai确定之后,那么pi和qi都必须小于等于ai,然后其中一个等于ai,另一个小于等于ai

其中一个等于ai后,如果后缀中没有ai了,那么另一个也可以等于ai

首先,将p中还没放置的数都放在set1中,将q中没放置的数都放在set2中,如果当前需要的数不在set1中,那么就需要q来放,如果当前的数在后面没有出现过,那么就p和q放一样的数
最后没有放的位置进行补数,当然得放比ai小的数,可以利用set自带的二分,最后检验

trick:

利用set的二分时,返回迭代器,进行迭代器的加减时特别注意是否越界

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=2e5+10;
int a[N];
int p[N],q[N];
int n;
void solve() {cin>>n;memset(p,0,sizeof p);memset(q,0,sizeof q);map<int,int>mp,mmp;for(int i=1;i<=n;i++) cin>>a[i],mp[a[i]]++;set<int>s1,s2;for(int i=1;i<=n;i++) s1.insert(i),s2.insert(i);for(int i=1;i<=n;i++){mmp[a[i]]++;if(s1.count(a[i])){p[i]=a[i];s1.erase(a[i]);if(mmp[a[i]]==mp[a[i]]&&s2.count(a[i])) q[i]=a[i],s2.erase(a[i]);}else if(s2.count(a[i])){q[i]=a[i];s2.erase(a[i]);}}for(int i=1;i<=n;i++){if(p[i]) continue;auto it=s1.lower_bound(a[i]);if(it==s1.begin()){cout<<"No"<<endl;return;}it--;p[i]=*it;s1.erase(it);}for(int i=1;i<=n;i++){if(q[i]) continue;auto it=s2.lower_bound(a[i]);if(it==s2.begin()){cout<<"No"<<endl;return;}it--;q[i]=*it;s2.erase(it);}for(int i=1;i<=n;i++){if(max(p[i],q[i])!=a[i]){cout<<"No"<<endl;return;}}cout<<"Yes"<<endl;for(int i=1;i<=n;i++) cout<<p[i]<<' ';cout<<endl;for(int i=1;i<=n;i++) cout<<q[i]<<' ';cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

24.D. Twist the Permutation

长度为n的排列,n在[2,2e3]
操作:n次操作,第i次操作将前i个数循环右移任意次数

问最后能否得到数组a,无解输出-1
输出位移总数最小的方案数

已知最终的结果,要求输出中间的过程->逆推

由于最终结果已知,第n个数是最后一次操作移动的,那么可以得到最后一次操作的最小循环右移次数,并推得最后一次操作前的序列,以此类推

trick:

1.已知最终的结果,要求输出中间的过程->逆推

2.用map预先记录每个数的位置,已知循环右移后的序列,可以快速得到循环右移的次数

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=2e3+10;
int a[N];
int ans[N];
int n;
void solve(){cin>>n;map<int,int>mp;for(int i=1;i<=n;i++) cin>>a[i],mp[a[i]]=i;for(int i=n;i>=1;i--){int res=mp[i]%i;//循环右移的次数ans[i-1]=res;//将1到i循环左移res回到上一状态,相当于循环右移i-resfor(int j=1;j<=i;j++){mp[j]=(mp[j]+i-res)%i;}}for(int i=0;i<n;i++) cout<<ans[i]<<' ';cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

25.D. Twist the Permutation

n * m的表格 (n和m均小于等于100)
均为0和1
数据小,考虑暴力

进行着色,0表示白色,1表示黑色
一开始全是0,即全是白色
操作:选择子矩形,将其变成国际象棋的颜色(左上角为白色)
输出着色方案,无解输出-1
最左上角的格子必须是0,否则直接-1

从后往前操作,用1 * 2的矩阵去涂色

坑点:

想到从后往前用1 * 2的矩阵,但是没想到可以用竖着的1 * 2矩阵

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=110;
char s[N][N];
int n,m;
struct node{int x1,y1,x2,y2;
};
void solve() {cin>>n>>m;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin>>s[i][j];}}if(s[1][1]=='1'){cout<<-1<<endl;return;}vector<node>ans;for(int i=n;i>=1;i--){for(int j=m;j>=1;j--){if(s[i][j]=='1'&&j>=2) ans.push_back({i,j-1,i,j});else if(s[i][j]=='1'&&j==1) ans.push_back({i-1,j,i,j});}}cout<<ans.size()<<endl;for(auto v:ans) cout<<v.x1<<' '<<v.y1<<' '<<v.x2<<' '<<v.y2<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

26.C. Divisor Chain

目标:将x减为1

可以减x的因子,但是同一个数最多只能减两次
最多需要减1000次,一定有解

由于任何一个数都都可以由若干个2的幂次构成
转化成2进制

先减到2的幂次,然后就好办了

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int x;
void solve() {cin>>x;string s;int a=x;int b=x;while(a){s=(char)((a&1)+'0')+s;a>>=1;}vector<int>ans;int len=s.size();//将x变为2的幂次for(int i=len-1;i>=1;i--){if(s[i]=='1') {ans.push_back(1ll<<(len-1-i));x-=(1ll<<(len-1-i));}}while(x!=1){ans.push_back(x/2);x/=2;}cout<<ans.size()+1<<endl;cout<<b<<' ';for(auto v:ans) cout<<b-v<<' ',b-=v;cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

27.C. Permutation Operations

长度为n的排列
操作:共n次操作,第i次操作选择一个非空后缀,将它们均加i(可以对同一后缀操作很多次)
使得逆序对数量最少

从大到小,整个后缀同时加应该是最优的,因为一下子就增加这么多的正序对
但是交上去错了,这样并不是最优的

发现我们完全可以让逆序对的数量为0

比如说5 3 2 4 1

我们可以让[2,5]都加5,即在第5次操作[2,5],在第3次操作[3,5],在第2次操作[4,5],在第4次操作[5,5]

比较巧妙,当作案例

trick:

两个相邻的数(均为正),要想让小的数大于大的数,让小数加上大的数

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=1e5+10;
int a[N];
int ans[N];
int n;
void solve() {cin>>n;memset(ans,0,sizeof ans);for(int i=1;i<=n;i++) cin>>a[i];for(int i=2;i<=n;i++) ans[a[i-1]]=i;for(int i=1;i<=n;i++){if(ans[i]) cout<<ans[i]<<' ';else cout<<1<<' ';}cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

28.C. Ehab and a Special Coloring Problem

构造一个序列,使得从下标2到n中,如果两个下标互质,那么两数不相等
使得序列的最大值最小,无解输出-1

相差为1的两个数互质
两个质数互质

所有质数都互质
所以全部偶数都放1,然后如果是质数的话,那么就依次放不同的数
如果是合数的话,那么就找它的因数,然后和它的因数放一样的答案

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=1e5+10;
int n;
int ans[N];
bool st[N];
int prime[N];
int cnt;
//欧拉筛
void get_prime(int n){for(int i=2;i<=n;i++){if(!st[i]) prime[cnt++]=i;for(int j=0;prime[j]<=n/i;j++){st[prime[j]*i]=true;if(i%prime[j]==0) break;}}
}
void solve() {cin>>n;get_prime(n);ans[2]=1;int idx=1;for(int i=3;i<=n;i++){if(!st[i]) ans[i]=++idx;else{for(int j=2;j<=i/j;j++){if(i%j==0){ans[i]=ans[j];break;}}}}for(int i=2;i<=n;i++) cout<<ans[i]<<' ';cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

29.B. Gardener and the Array

长度为n的数组c

问是否有两个不同的子序列,f(a)= f(b),f是将所有数或
只要索引不完全一样,子序列就不同

或:有1出1

如果某个数该位上就它为1,那么称这个数是必要的

如果所有数都是必要的,那么不可能有两个不同的子序列,f(a)= f(b),f是将所有数或

否则可以令a为整个序列,b为在a中剔除一个非必要的

trick:
1.如果想看某位是不是就一个数为1,可以用map桶计数,来记录有多少个数在该位上为1

2.位运算一般的技巧是将所有数都位运算

3.或是有1出1,只要数a某位上已经为1了,那么只要或上了a,那么该位一定为1,如果b该位也为1,其它位为0,那么或上b结果不变,就称b是非必要的

如果某位就数c为1的话,那么就称c是必要的

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n;
void solve() {cin>>n;vector<vector<int>>e(n+1);map<int,int>mp;for(int i=0;i<n;i++){int k;cin>>k;for(int j=0;j<k;j++){int x;cin>>x;e[i].push_back(x);mp[x]++;}}int cnt=0;for(int i=0;i<n;i++){for(int j=0;j<(int)e[i].size();j++){if(mp[e[i][j]]==1){cnt++;break;}}}if(cnt==n) cout<<"No"<<endl;else cout<<"Yes"<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

30.C. Ice and Fire

依次枚举,如果当前为0的话,然后看已经几个连续的0就需要连续靠0赢几次,同理,看几个连续的1就靠1赢几次

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=2e5+10;
int n;
int ans[N];
string s;
void solve() {cin>>n;cin>>s;s=' '+s;int cnt_0=0,cnt_1=0;for(int i=1;i<=n-1;i++){if(s[i]=='0'){//当前为0,看有几个连续的0cnt_0++;ans[i+1]=i+1-cnt_0;cnt_1=0;} else {cnt_1++;ans[i+1]=i+1-cnt_1;cnt_0=0;}}for(int i=2;i<=n;i++) cout<<ans[i]<<' ';cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

31.A. Qingshan Loves Strings 2

长度为n的01串
数据比较小,考虑暴力

好字符串:所有对称的字符均不相等
操作:在任意位置插入01
无解输出-1,有解肯定在300次操作以内

暴力模拟

trick:

string的insert函数:s.insert(pos,tmp) 将tmp字符串插入在下标为pos的前面

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n;
string s;
void solve() {cin>>n;cin>>s;vector<int>ans;int cnt=0;//操作了几次//对称的下标相加为s.size()-1for(int i=0;i<(int)s.size();i++){if(s[i]==s[(int)s.size()-1-i]){if(i==0){string tmp="01";if(s[0]=='1') s=tmp+s,ans.push_back(0),i=0;else ans.push_back((int)s.size()),s+=tmp;}else{if(s[i]=='0'){int pos=(int)s.size()-1-i;//在pos后面插入01string tmp="01";s.insert(pos+1,tmp);ans.push_back(pos+1);}else{int pos=i;//在pos前面插入01string tmp="01";s.insert(pos,tmp);ans.push_back(pos);i-=2;}}cnt++;if(cnt>300) break;}}for(int i=0,j=(int)s.size()-1;i<=j;i++,j--){if(s[i]==s[j]){cout<<-1<<endl;return;}		}cout<<ans.size()<<endl;for(auto v:ans) cout<<v<<' ';cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

32.B. New Year’s Eve

1到n共n个数
从中最多选取k个数,使得选取的所有数异或和最大

最大的数为n,假设n转化成二进制一共cnt位,异或是按位异或,不可能可以进位,所以最多也就cnt位,那么最大也就是cnt位全都为1

那么只要选两个数,一个数为n,另一个数只要把n为0的位补成1就行了

trick:

位运算是按位的,对于参与位运算的若干数,首先最大的那个数转化成二进制后最左边那位肯定是1(忽略前导0),假设共cnt位,按位运算是不可能进位的,所以这些数进行位运算最大也就是cnt位全部为1

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n,k;
void solve() {cin>>n>>k;int ans=0;int num=1;if(k==1){cout<<n<<endl;return;}while(n){ans^=num;num<<=1;n>>=1;}cout<<ans<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

33.C. Insert Zero and Invert Prefix

长度为n的01序列
操作:n次操作,第i次操作在0到i-1之间选择一个整数p,在序列b的p位置后插入0,并反转它前面所有元素

最后一个必须是0,否则无解

从后往前,数连续1的个数cnt,可以先产生cnt个0,然后将cnt个0反转为1

trick:

1.操作是插入一个0并将前缀反转,并不会影响后面的序列,考虑从后往前

2.01反转,考虑一段一段,连续cnt个1可以将连续cnt个0进行一次反转操作

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=1e5+10;
int a[N];
int n;
void solve() {cin>>n;for(int i=1;i<=n;i++) cin>>a[i];if(a[n]==1){cout<<"NO"<<endl;return;}cout<<"YES"<<endl;int cnt=0;for(int i=n-1;i>=0;i--){if(a[i]==1){cnt++;cout<<0<<' ';}else{cout<<cnt<<' ';cnt=0;}}cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

34.B. Binary String Constructing

构造长度为a+b的01串,刚好a个0,b个1
刚好有x对相邻对不相等
一定有解

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int a,b,x;
void solve() {cin>>a>>b>>x;if(a<=b){//1比较多if(x%2==1){for(int i=0;i<x/2;i++) cout<<"10";for(int i=0;i<b-x/2;i++) cout<<1;for(int i=0;i<a-x/2;i++) cout<<0;cout<<endl;}else{for(int i=0;i<x/2;i++) cout<<"10";for(int i=0;i<a-x/2;i++) cout<<0;for(int i=0;i<b-x/2;i++) cout<<1;cout<<endl;}}else{if(x%2==1){for(int i=0;i<x/2;i++) cout<<"01";for(int i=0;i<a-x/2;i++) cout<<0;for(int i=0;i<b-x/2;i++) cout<<1;cout<<endl;}else{for(int i=0;i<x/2;i++) cout<<"01";for(int i=0;i<b-x/2;i++) cout<<1;for(int i=0;i<a-x/2;i++) cout<<0;cout<<endl;}}
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

35.A. Packets

n个硬币

将n枚硬币分成若干组,使得1到n这些数都可以由某几组构成
求最少分成几组

要使组数最少,那么每组硬币数可以跨度大一些,想到2的幂次

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n;
void solve() {cin>>n;int ans=0;for(int i=0;;i++){int x=(1ll<<i);if(n>=x){ans++;n-=x;}else break;}if(n) ans++;cout<<ans<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

36.C. Insert and Equalize

长度为n的数组a(数[-1e9,1e9])每个数均不同
操作:
首先在末尾加入一个没出现过的数,选择一个正整数x
然后每次操作将x加到其中一个元素上

目标是让所有元素相等,问最少操作几次

先排个序
只能变大,不能变小,那么就都变成最大的那个

要使操作次数少,那么每次加的数要大一些,所有其它数和最大值的差值的gcd即为x,得到x之后就很简单了

那么有没有可能a[n+1]作为最大的数,然后其它n个数和a[n+1]的差值全部取gcd会更大呢?

不可能!!!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

trick:

直接理解记忆这张图

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=2e5+10;
int a[N];
int n;
int gcd(int a,int b){if(b==0) return a;return gcd(b,a%b);
}
void solve() {cin>>n;map<int,int>mp;for(int i=1;i<=n;i++) cin>>a[i],mp[a[i]]++;if(n==1){cout<<1<<endl;return;}sort(a+1,a+1+n);int x=0;for(int i=1;i<=n-1;i++){x=gcd(x,a[n]-a[i]);}int res=a[n];while(mp[res]){res-=x;}int ans=0;for(int i=1;i<=n;i++){ans+=(a[n]-a[i])/x;}ans+=(a[n]-res)/x;cout<<ans<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

37.B. Vasya and Isolated Vertices

由n个顶点,m条边组成的无向图
求孤立顶点的最少和最多数量

最多:x个顶点连成完全无向图,所用边数大于等于m,然后剩下节点成为孤立节点
最少:两两顶点一对,用一条边,n-m*2

trick:

图论一定要有特判,n为1和m为0

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n,m;
int cal(int x){//x个顶点return x*(x-1)/2;//成为完全无向图需要的边数
}
void solve() {cin>>n>>m;if(m==0){cout<<n<<' '<<n<<endl;return;}int l=1,r=n;while(l<r){int mid=(l+r)/2;if(cal(mid)>=m) r=mid;else l=mid+1;}cout<<max(0ll,n-m*2)<<' '<<max(0ll,n-l)<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

38.A. Fill in the Matrix

n*m的矩阵
每一行要求是1到m的排列
vi是第i列mex值
beauty:v1到vm的mex
要求使mex最大

构造矩阵

0 1 2 3
1 2 3 0
2 3 0 1
先构造m-1行
再0 1 2 3重复
答案为m+1

0 1 2 3
1 2 3 0
不够m-1行,答案为n+1

0 1 2 3 4
1 2 3 4 0

特判m为1的情况

trick:

1.构造矩阵,一边遍历一边输出,很少存到数组再输出的

2.构造矩阵,一般要特判n为1,m为1

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n,m;
void solve() {cin>>n>>m;if(m==1){cout<<0<<endl;for(int i=0;i<n;i++) cout<<0<<endl;return;}if(n<m-1){cout<<n+1<<endl;for(int i=0;i<n;i++){for(int j=0;j<m;j++){cout<<(j+i)%m<<' ';}cout<<endl;}}else{cout<<m<<endl;for(int i=0;i<m-1;i++){for(int j=0;j<m;j++){cout<<(j+i)%m<<' ';}cout<<endl;}for(int i=0;i<n-(m-1);i++){for(int j=0;j<m;j++){cout<<j<<' ';}cout<<endl;}}
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

39.B. Bit Flipping

长度为n的01串

操作:选择一位不反转,其余位均反转
一共操作k次,使得字典序最大

01反转看奇数次,偶数次,如果反转奇数次,那么反转,否则不变
尽可能把前面的0 变成1
总反转次数为k,该位的反转次数即为k减去该位上的数字
从前往后遍历,如果是1的话,就需要保持不变,如果k为奇数,那么该位先放个1,使得该位操作次数为偶数 ,如果k为偶数,那么该位不用放数字
如果是0的话,就需要反转,如果k为奇数,那么该位不用放数字,如果k为偶数 ,那么该位放个1,最后如果k还有剩余,那么就全放在最后一位

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=2e5+10;
int ans[N];
int n,k;
string s;
void solve() {cin>>n>>k;cin>>s;memset(ans,0,sizeof ans);int tmp=k;for(int i=0;i<n;i++){if(s[i]=='1'){if(tmp&&k%2) ans[i]=1,tmp--;else if(tmp&&k%2==0) ans[i]=0;}else{if(tmp&&k%2) ans[i]=0;else if(tmp&&k%2==0) ans[i]=1,tmp--;}if(!tmp) break;}ans[n-1]+=tmp;for(int i=0;i<n;i++){if((k-ans[i])%2){if(s[i]=='1') s[i]='0';else s[i]='1';}}cout<<s<<endl;for(int i=0;i<n;i++) cout<<ans[i]<<' ';cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

40.A. Oh Those Palindromes

长度为n的字符串,由小写字母组成

回文计数:回文子串的个数
重新排列字符串,使得回文子串个数最多

aabbccddfgggghhh

16+2+1+1+1+1+6+3

aabb

abba

枚举了好几种情况,发现都是一样的排在一起是最多的

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n;
string s;
void solve() {cin>>n;cin>>s;multiset<char>s1;for(int i=0;i<n;i++) s1.insert(s[i]);for(auto v:s1) cout<<v;cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

41.C. Salyg1n and the MEX Game

共n个不同的整数在集合S中
Alice和Bob博弈
Alice先行

Alice在集合S中添加一个S中没出现过的正整数x([0,1e9])
Bob在集合S中移除一个数y,y必须严格小于S中的最后一个数

当Bob移除不了数或者Alice走了n+1步,游戏结束,结果为mex(S)

Alice使结果最大化,Bob使结果最小化

Alice先行,先补上mex

然后当Bob移除一个数,Alice就把那个数加回来

trick:

1.交互题,程序中需要输入的就正常输入,需要输出的就在每个输出语句后面加上一句cout.flush();

2.博弈题,如果按照最优策略的话,根据对方来出招,比如说我方为增加,对方为移除,我方增加肯定是有利于我方的,对方移除肯定是有利于对方的,可以当对方移除时,我们就加回来是一个很好的策略

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=1e5+10;
int a[N];
int n;
void solve() {cin>>n;map<int,int>mp;for(int i=1;i<=n;i++) cin>>a[i],mp[a[i]]=1;int x;//没有出现的第一个数for(int i=0;i<n;i++){if(!mp[i]){x=-1;break;}}cout<<x<<endl;fflush(stdout);int y;while(cin>>y){if(y<0) break;cout<<y<<endl;fflush(stdout);}
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;cin>>t;while(t--) {solve();}return 0;
}

42.C. Labs

nn个实验室建在不同的高度,1到nn,高度依次递增

高处的实验室可以向低处的实验室输送水,一次输送一单位的水

将n*n个实验室分成n组,每组包含n个实验室
f(A,B):A组向B组输水,可以输多少单位的水

构造一种分组,使得任意两组的f,所有情况取min,尽可能大

从样例寻求到了一种构造方法:
1到n分别放在每一组中
n+1到2*n分别放到每一组中
以此类推
放的方式是正序,逆序,正序,逆序…

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n;
void solve() {cin>>n;int flag=1;vector<vector<int>>e(n+1);int cnt=0;for(int i=1;i<=n;i++){//共n组if(flag){//正序for(int j=1;j<=n;j++){e[j].push_back(++cnt);}}else{for(int j=n;j>=1;j--){e[j].push_back(++cnt);}}flag^=1;}for(int i=1;i<=n;i++){for(auto v:e[i]) cout<<v<<' ';cout<<endl;}
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

43.B. Painting Pebbles

一共n堆鹅卵石
ai为第i堆鹅卵石的数量
构造用k种颜色给每颗鹅卵石上色
使得任意两堆鹅卵石中颜色c的数量最多差1个,要求k种颜色都满足,无解输出NO

平均分配
一遍一遍遍历,只要每组都还有石头可涂,那么每组涂一个(用同一种颜色)
只要有任何一组没有石头可涂,那么这组涂完之后(用同一种颜色),就换颜色
直到所有的石头都被涂上色
如果颜色不够了,就无解

数据比较小,直接暴力

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=110;
int a[N];
int n,k;
void solve() {cin>>n>>k;int color=1;int sum=0;for(int i=1;i<=n;i++) cin>>a[i],sum+=a[i];vector<vector<int>>ans(n+1);int cnt=0;//涂了几个石头while(1){bool ok=true;for(int i=1;i<=n;i++){if((int)ans[i].size()<a[i]){//还有石头可涂ans[i].push_back(color);cnt++;}else ok=false;}if(!ok) color++;if(color>k||cnt==sum) break;}if(cnt<sum){cout<<"NO"<<endl;return;}cout<<"YES"<<endl;for(int i=1;i<=n;i++){for(auto v:ans[i]) cout<<v<<' ';cout<<endl;}
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

44.B. Sonya and Exhibition

长度为n的01串
beauty:[l,r]中0的个数和1的个数的乘积
给定m个区间

构造01串,使得m个区间美之和最大

和一定,差越小,积越大
0和1平均分配

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n,m;
void solve() {cin>>n>>m;while(m--){int l,r;cin>>l>>r;}int flag=1;for(int i=0;i<n;i++){if(flag) cout<<1;else cout<<0;flag^=1;}cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

45.A. Difference Row

长度为n的数组a(数[-1000,1000])n大于等于2

排列,使得相邻两数差(前一个减后一个)之和最大,并且排列的字典序最小

最后的值为x1-xn,所以x1放最大,xn放最小,由于要字典序最小,中间升序

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=110;
int a[N];
int n;
void solve() {cin>>n;for(int i=1;i<=n;i++) cin>>a[i];sort(a+1,a+1+n);reverse(a+1,a+1+n);vector<int>ans;for(int i=2;i<=n-1;i++) ans.push_back(a[i]);sort(ans.begin(),ans.end());cout<<a[1]<<' ';for(int i=0;i<(int)ans.size();i++) cout<<ans[i]<<' ';cout<<a[n]<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

46.B. Neko Performs Cat Furrier Transform

对于正整数x(数[1,1e6])
完美长猫数:转化为二进制数全为1
操作:A.将x和一个完美长猫数异或 B.+1

第奇数次操作A,第偶数次操作B
最多执行40次,一定有解
将x变成完美长猫数

和1异或相当于01反转
从高位到低位一位一位反转

但是要注意,加1可能会进位,导致前面的1变成0,所以每次都从最高位开始找

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int x;
void solve() {cin>>x;int xx=x;int xxx=x;int cnt=-1;//x转化为二进制最高位是第几位while(xx){cnt++;xx>>=1;}vector<int>ans;while(x&(x+1)){for(int i=cnt;i>=0;i--){if((x&(1ll<<i))==0){//如果该位是0的话,就反转为1x^=((1ll<<(i+1))-1);if(x&(x+1)) x++;ans.push_back(i+1);}}}if(xxx%2==0) cout<<ans.size()*2-1<<endl;else cout<<ans.size()*2<<endl;for(auto v:ans) cout<<v<<' ';cout<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

47.C. Dividing the numbers

将1到n分到两个集合中,两个集合都不能为空,使得两组整数之和的差值最小

任意四个连续的数,x,x+1,x+2,x+3,可得x+x+3=x+1+x+2

所以每四个连续的数可以抵消,最后看n%4即可

trick:

任意四个连续的数,x,x+1,x+2,x+3,可得x+x+3=x+1+x+2

#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n;
void solve() {cin >> n;int x = n % 4;if (x == 1 || x == 2) cout << 1 << endl;else cout << 0 << endl;vector<int>ans;for (int i = n; i >= 4; i -= 4) {ans.push_back(i);ans.push_back(i - 3);}if (x == 3) ans.push_back(3);else if (x == 2) ans.push_back(2);cout << ans.size() << ' ';for (auto v : ans) cout << v << ' ';cout << endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t = 1;
//    cin>>t;while (t--) {solve();}return 0;
}

48.A. Lucky Permutation Triple

构造三个长度为n的排列,0到n-1各出现一次
满足任意i,(ai+bi)%n = ci
无解输出-1

当n为奇数时,可以构造a为0到n-1,b为0到n-1
猜测n为偶数时无解

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n;
void solve() {cin>>n;if(n%2){for(int i=0;i<n;i++) cout<<i<<' ';cout<<endl;for(int i=0;i<n;i++) cout<<i<<' ';cout<<endl;for(int i=0;i<n;i++) cout<<i*2%n<<' ';cout<<endl;}else cout<<-1<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

49.B. Students in Railway Carriage

有n个连续的座位,.表示位置是空的,*表示有人

a名学生程序员,b名学生运动员,问最多有几人可以做到座位上,学生程序员不能连续,学生运动员不能连续

交替放置
优先放多的那个
取出一段一段连续的.

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n,a,b;
string s;
void solve() {cin>>n>>a>>b;cin>>s;if(a<b) swap(a,b);vector<int>ans;//存放大于等于2的int sum=0;//统计等于1的个数int cnt=0;for(int i=0;i<n;i++){if(s[i]=='.') cnt++;else{if(cnt>=2) ans.push_back(cnt);else if(cnt==1) sum++;cnt=0;}}if(cnt>=2) ans.push_back(cnt);else if(cnt==1) sum++;int res=0;for(int i=0;i<(int)ans.size();i++){int flag=1;if(a<b) swap(a,b);//每次优先填大的for(int j=0;j<ans[i];j++){if(flag){if(a){res++;a--;}}else{if(b){res++;b--;}}flag^=1;}}//为1的填什么都行int res1=a+b;//剩下的res+=min(res1,sum);cout<<res<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

50.B. Vika and Squares

一共有n个带颜色的罐子
ai表示颜色i罐子油漆的升数
从左到右给正方形涂颜料,一个正方形需要1升,必选按照x+1的循环顺序,起点颜料自定
问最多可以涂多少个正方形

取所有数的最小值minn,首先minn轮一定是可以的,然后就会出现很多个0造成阻断,那么只要统计连续非0个数最多是多少

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=2e5+10;
int a[2*N];
int n;
void solve() {cin>>n;int ans=0;int minn=2e9;for(int i=1;i<=n;i++) cin>>a[i],minn=min(minn,a[i]);for(int i=1;i<=n;i++) a[i]-=minn;for(int i=n+1;i<=2*n;i++) a[i]=a[i-n];ans+=minn*n;int cnt=0;int maxn=0;for(int i=1;i<=2*n;i++){if(a[i]) cnt++;else{maxn=max(maxn,cnt);cnt=0;}}if(cnt) maxn=max(maxn,cnt);cout<<ans+maxn<<endl;
}
signed main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t=1;
//    cin>>t;while(t--) {solve();}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/452740.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nginx日志格式脚本

​ Nginx日志主要分为两种&#xff1a; access_log&#xff08;访问日志&#xff09;&#xff1a;记录客户端请求的信息&#xff0c;可以指定 log_format。 error_log&#xff08;错误日志&#xff09;&#xff1a;记录应用程序问题等信息&#xff0c;不可以指定log_format …

2024最新最详细【接口测试总结】

序章 ​ 说起接口测试&#xff0c;网上有很多例子&#xff0c;但是当初做为新手的我来说&#xff0c;看了不不知道他们说的什么&#xff0c;觉得接口测试&#xff0c;好高大上。认为学会了接口测试就能屌丝逆袭&#xff0c;走上人生巅峰&#xff0c;迎娶白富美。因此学了点开发…

Leetcode24:两两交换链表中的节点

一、题目 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例&#xff1a; 输入&#xff1a;head [1,2,3,4] 输出&#xff…

101 C++内存高级话题 内存池概念,代码实现和详细分析

零 为什么要用内存池&#xff1f; 从前面的知识我们知道&#xff0c;当new 或者 malloc 的时候&#xff0c;假设您想要malloc 10个字节&#xff0c; char * pchar new char[10]; char *pchar1 malloc(10); 实际上编译器为了 记录和管理这些数据&#xff0c;做了不少事情&…

undefined symbol: avio_protocol_get_class, version LIBAVFORMAT_58

rv1126上进行编译和在虚拟机里面进行交叉编译ffmpeg都不行 解决办法查看 查看安装的ffmpeg链接的文件 ldd ./ffmpeg rootEASY-EAI-NANO:/home/nano/ffmpeg-4.3.6# ldd ffmpeg linux-vdso.so.1 (0xaeebd000)libavdevice.so.58 > /lib/arm-linux-gnueabihf/libavde…

斗破年番:七星斗宗地魔老鬼,首战吊打萧炎,毁灭莲逼出千百二老

Hello,小伙伴们&#xff0c;我是拾荒君。 国漫《斗破苍穹年番》第82期超前爆料&#xff0c;在万众瞩目之下&#xff0c;卡点帝再次展现了他的卡点救场技巧。此次&#xff0c;韩枫为了除掉萧炎&#xff0c;以他击杀魔炎谷四位长老为借口&#xff0c;请来了七品斗宗地魔老鬼。更…

LabVIEW与EtherCAT实现风洞安全联锁及状态监测

LabVIEW与EtherCAT实现风洞安全联锁及状态监测 在现代风洞试验中&#xff0c;安全联锁与状态监测系统发挥着至关重要的作用&#xff0c;确保了试验过程的安全性与高效性。介绍了一套基于EtherCAT总线技术和LabVIEW软件开发的风洞安全联锁及状态监测系统。该系统通过实时、可靠…

redis的缓存击穿和缓存雪崩和缓存穿透问题解决方法

Redis的缓存击穿&#xff1a; 热点的key&#xff0c;在不停的扛着大并发&#xff0c;当这个key失效时&#xff0c;一瞬间大量的请求冲到持久层的数据库中&#xff0c;就像在一堵墙上某个点凿开了一个洞&#xff01; 解决方法&#xff1a; 1.热点key永不过期&#xff1a; 统计访…

彻底扒光QQ音乐,批量下载音乐和MV文件

购买了一年的QQ音乐绿钻豪华版&#xff0c;还有几天就到期了&#xff0c;虽然平时听音乐比较少&#xff0c;但是还比较喜欢听歌曲的。计划会员到期前下载一些音乐文件&#xff0c;继续针对QQ音乐网站源码分析和歌曲下载链接的进行研究。 平时通过APP和软件播放歌曲也是趋势&…

面试数据结构与算法总结分类+leetcode目录【基础版】

&#x1f9e1;&#x1f9e1;&#x1f9e1;算法题目总结&#xff1a; 这里为大家总结数据结构与算法的题库目录&#xff0c;如果已经解释过的题目会标注链接更新&#xff0c;方便查看。 数据结构概览 Array & String 大家对这两类肯定比较清楚的&#xff0c;同时这也是面试…

bert分类模型使用

使用 bert-bert-chinese 预训练模型去做分类任务&#xff0c;这里找了新闻分类数据&#xff0c;数据有 20w&#xff0c;来自https://github.com/649453932/Bert-Chinese-Text-Classification-Pytorch/tree/master/THUCNews 数据 20w &#xff0c;18w 训练数据&#xff0c;1w 验…

ddddocr验证码识别模块

ddddocr验证码识别模块 简介 ddddocr是一个基于深度学习的OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;工具&#xff0c;主要用于中文场景文字识别。能够对图片中的文字进行识别并提取出来。 ddddocr模块主要特点包括&#xff1a; 适用…