文章目录
前言
刷题结合知识点学习——数论,字符串处理,搜索,DP,计算几何,规律题。
各种错误(堆栈溢出,段错误…)
7.18早上,刷不下去了,整理一下。刷题刷到心态爆炸。
一、Codeforces:
1.A. Find The Array
题目大意: 定义一个“beautiful”数组,满足里头的元素要么为1,要么ai-1或者ai-2在数组中存在。输入数组的总和s,输出数组最小的大小其元素总和等于s,数组需为“beautiful”数组。
大致思路:s不大,0<=s<=5000,这里数组里全部取奇数和全部取偶数是一样的,都满足“beautiful”的条件,这里以奇数为例:前n项奇数的和为:n*n,找到大于等于s的最小n,即为答案。(至于这里为什么是:找到大于等于s的最小n,原因在于若找到一个n,n×n<s且(n+1)×(n+1)>s则总可在n的基础上补上一个偶数a,满足n×n+a==s,即n+1个数)
AC的代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int s[100];
// 这里先打表,到时候直接查询就行了.
void init(){
for(int i=1;i<=73;i++){
s[i] = i*i;
}
}
int main()
{
init();
// for(int i=1;i<=72;i++){
// cout << s[i] << endl;
// }
int t;
scanf("%d",&t);
int a,ans;
while(t--){
ans = 0;
scanf("%d",&a);
for(int i=1;i<=72;i++){
if(s[i]>=a){
ans += i;
break;
}
}
printf("%d\n",ans);
}
return 0;
}
2.B. Maximum Cost Deletion
题目大意:给定一个01串,每次删除相同的子串(0串或1串),每删除一次,计算一次分数a×l+b(l为删除的长度),给定a,b计算最大分数。
大致思路:分情况讨论:当b>=0时,ans=n*(a+b);当b<0时,统计0子串和1子串的个数,ans = na + b(min(cnt0,cnt1)+1)。
AC的代码
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
long long ans;
int t;
scanf("%d",&t);
int n,a,b,cnt0,cnt1;
char book = 'w';
string s;
while(t--){
ans = 0;
scanf("%d%d%d",&n,&a,&b);
cin >> s;
if(b>=0){
ans = n*(a+b);
}else{
book = -1;
cnt0 = 0,cnt1 = 0;
for(int i=0;s[i];i++){
if(s[i]!=book){
if(s[i]=='0'){
cnt0++;
}else{
cnt1++;
}
book = s[i];
}
}
ans = n*a + b*(min(cnt0,cnt1)+1);
}
printf("%d\n",ans);
}
return 0;
}
3.C. Manhattan Subarrays
题目大意:
定义曼哈顿距离:d(p,q)=|xp−xq|+|yp−yq|;
定义good数组:不可能挑出三个元素(下标为p,q,r)使d(p,r)=d(p,q)+d(q,r)。注:数组大小为1,2的子数组均为good数组。
给定一个数组,计算good子数组的个数。
大致思路:
第一次感觉样例有问题,反复读题,一直没找出问题,直到第二天再读题,还是没有看出什么问题,直到刚刚才发现问题所在:取出的子元素必须是连续的。
找出规律,good数组的大小最大为4。连续的话,从左向右取就好了。ans初始先统计大小为1和2的子数组的个数。
AC的代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[300010];
int main()
{
int t,n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
int res = 2*n - 1;
for(int i=1;i<n-1;i++){
if(a[i]>a[i-1]&&a[i]>a[i+1]){
// cout << a[i-1] << " " << a[i] << " " << a[i+1] << endl;
res++;
if(n>i+2&&a[i-1]>a[i+1]&&a[i]>a[i+2]&&a[i+1]<a[i+2]){
// cout << a[i-1] << " " << a[i] << " " << a[i+1] << " " << a[i+2] << endl;
res++;
}
}
if(a[i]<a[i-1]&&a[i]<a[i+1]){
// cout << a[i-1] << " " << a[i] << " " << a[i+1] << endl;
res++;
if(n>i+2&&a[i-1]<a[i+1]&&a[i]<a[i+2]&&a[i+1]>a[i+2]){
// cout << a[i-1] << " " << a[i] << " " << a[i+1] << " " << a[i+2] << endl;
res++;
}
}
}
printf("%d\n",res);
}
return 0;
}
4.B. AquaMoon and Stolen String
题目大意:
输入n和m,n表示n个字符串,n为奇数,m表示字符串的长度
之后输入n个字符串,表示原字符串;再输入n-1个字符串,表示交换后的字符串(两两交换,只有一个串没被交换过)
找出那个没被交换过的字符串。
大致思路:
1.一开始思路错误:借用了桶排序的思想;即把原始字符串的每个字符的个数都统计出来,再减去交换过的字符串的每个字符的数量。但问题在于,答案让输出没被交换过的串,这样做无形中打乱的未被交换过的串的顺序,使其按照字典序输出了。
2.进行思路修正后,利用位运算 ^ 的思想,a ^ b ^ a = b ,以字符为一个单位的话,不管进行如何的交换,交换过的字符都会出现两次或者偶数次,没交换过的都会出现奇数次或一次。这里把字符映射为数字进行处理。
AC的代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef unsigned long long ull;
ull a[100010];
char s[100010];
int main()
{
int t;
cin >> t;
int n,m;
while(t--){
memset(a,0,sizeof(a));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf(" %s",s);
for(int j=0;j<m;j++)
a[j] += s[j] - 'a' + 1;
}
for(int i=1;i<n;i++){
scanf(" %s",s);
for(int j=0;j<m;j++)
a[j] -= s[j] - 'a' + 1;
}
for(int i=0;i<m;i++){
printf("%c",(char)(a[i]-1+'a'));
}
printf("\n");
}
return 0;
}
5.A. AquaMoon and Two Arrays
题目大意:
定义一种操作:取i,j,令ai-1,aj+1;
给定两个数组a,b;问a能否通过有限次操作到达b,若能输出操作次数m及m次操作,否则输出-1.
大致思路:
水题飘过,若两个数组的和相等,则一定能到达,反之不能。
具体实行:计算a,b数组每个位置的差值,存到c数组里头;每次取c[k]<0输出为j,后c[k]++;c[p]>0输出为i,c[p]–,直到每个元素都为0为止.
AC的代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[105],b[105],c[105];
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t,n;
cin >> t;
int sum1,sum2,ans;
while(t--){
ans = 0;
cin >> n;
sum1 = 0,sum2 = 0;
for(int i=1;i<=n;i++){
cin >> a[i];
sum1 += a[i];
}
for(int i=1;i<=n;i++){
cin >> b[i];
c[i] = a[i] - b[i];
sum2 += b[i];
}
for(int i=1;i<=n;i++){
if(c[i]>0){
ans += c[i];
}
}
int j;
if(sum1!=sum2){
cout << "-1" << endl;
}else{
cout << ans << endl;
for(int i=1;i<=n;i++){
while(c[i]>0){
for(j=1;j<=n;j++){
if(c[j]<0)
break;
}
cout << i << " " << j << endl;
c[i]--;
c[j]++;
}
}
}
}
return 0;
}
6. AquaMoon and Strange Sort
题目大意:
给定一个数组,每个元素都有一个方向(开始均向右)。通过交换相邻两个数组元素,使数组构成一个非递减序列,且方向向右。可以则输出YES,否则输出NO。
大致思路:倘若交换两个元素,则这两个元素必交换偶数次。
先sort一下,后计算开始每个元素距离目标位置的距离。从右往左开始计算距离ds,判断ds的奇偶性。
每个元素相距目标位置距离都为0或者偶数个单位时输出YES,否则输出NO。
AC的代码:
// 每个元素相距目标位置距离都为0或者偶数个单位时输出YES,否则输出NO。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100010;
int a[N],b[N];
int p[N][2];
int main()
{
int t,n;
scanf("%d",&t);
while(t--){
memset(p,0,sizeof(p));
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
b[i] = a[i];
}
sort(b,b+n);
for(int i=0;i<n;i++){
p[a[i]][i&1]--;
cout << "a[i]=" << a[i] << " p[a[i]][i&1]=" << p[a[i]][i&1] << endl;
}
int flag = 1;
for(int i=0;i<n;i++){
if(p[b[i]][i&1]<0) p[b[i]][i&1]++;
//原来位置和目标位置的距离为偶数时i&1值相同
else flag = 0;
}
puts(flag?"YES":"NO");
}
return 0;
}
总结:
先写这么多吧,下午写在牛客刷的题。