CSP-M3

题目1,2

题目大意与思路
  1. 第一题:瑞神想到了一个序列,这个序列长度为n,也就是一共有n个数,瑞神给自己出了一个问题:数列有几段?一段就是连续且相同的一段数,输入第一行一个整数n,表示数的个数,接下来一行n个空格隔开的整数,表示不同的数字,输出一行,这个序列有多少段
    思路:遇见不同的数字,就令cnt++,直接模拟即可

  2. 第二题:游戏在一个包含有 n 行 m 列的棋盘上进行,棋盘的每个格子都有一种颜色的棋子。当一行或一列上有连续三个或更多的相同颜色的棋子时,这些棋子都被消除。当有多处可以被消除时,这些地方的棋子将同时被消除。一个棋子可能在某一行和某一列同时被消除。
    思路:对每一行和每一列使用类似滑动窗口的思想,遇到重复的,且大于等于3个数的情况下,就把这一段的数全部置零,为了便于处理行列中有重复元素的情况,所以,不直接在原数组中里直接改动,而是建一个备份,考察原数组,在备份里更改,这样即使行列中有重复的元素,也是两次置零而已。

代码

第一题:

#include<cstdio>
#include<cstring>
using namespace std;
int n=0,cnt=0,x=0;
int a[2000];
int main() 
{
 memset(a,0,sizeof a);
 scanf("%d",&n);
 for(int i=0;i<n;i++){
  scanf("%d",&a[i]);
  if(i==0){
   x=a[i]; cnt++;
  }
  else{
   //if(x==a[i])
   if(x!=a[i]) {
    cnt++;
    x=a[i];
   }
  }
 }
 printf("%d",cnt);
 return 0;
}

第二题:

#include<cstdio>
using namespace std;
int n,m;
int a[50][50];
int ans[50][50];
void solve()
{
 int l=0,r=0;
 for(int i=0;i<n;i++){
  l=0,r=0;
  while(r<m){
   if(a[i][l]==a[i][r]) r++;
   else {
    if(r-l>=3){
      for(int k=l;k<r;k++) ans[i][k]=0;
    }
    l=r;
   }
  }
  if(r-l>=3){
   for(int k=l;k<r;k++) ans[i][k]=0;
  }
 }
    l=0,r=0;
 for(int j=0;j<m;j++){
  l=0,r=0;
  while(r<n){
   if(a[l][j]==a[r][j]) r++;
   else {
    if(r-l>=3){
      for(int k=l;k<r;k++) ans[k][j]=0;
    }
    l=r;
   }
  }
  if(r-l>=3){
   for(int k=l;k<r;k++) ans[k][j]=0;
  }
 }
}
int main() 
{
// freopen("in.txt","r",stdin);
 scanf("%d%d",&n,&m);
 for(int i=0;i<n;i++)
   for(int j=0;j<m;j++){
     scanf("%d",&a[i][j]);
     ans[i][j]=a[i][j];
   }
 solve();
 for(int i=0;i<n;i++){
  for(int j=0;j<m;j++){
    if(j!=0) printf(" ");
    printf("%d",ans[i][j]);
   }
   if(i!=n-1) printf("\n");
 }   
 return 0;
}

第三题

题目大意

今天TT打算教咕咕东字母A和字母B,TT给了咕咕东一个只有大写A、B组成的序列,让咕咕东分辨这些字母。
咕咕东问TT这个字符串有多少个子串是Delicious的。
Delicious定义:对于一个字符串,我们认为它是Delicious的当且仅当它的每一个字符都属于一个被完整包含于字符串的大于1的回文子串中。
输入第一行一个正整数n,表示字符串长度
接下来一行,一个长度为n只由大写字母A、B构成的字符串。
输出仅一行,表示符合题目要求的子串的个数。

思路

这个题考试的时候,把注意力都放到了回文子串上,导致思路想偏了,这道题实质是首先使用的正难则反的思想,找出所有不符合要求的子串,用总的子串数量-减去不符合要求的子串数量。
总的子串数量是: n ( n + 1 ) / 2 n(n+1)/2 n(n+1)/2。不符合要求的子串,说明子串中一定含有AB的分界点:…A|B…, 或…B|A…, 所以假设S(1)与S(2)是处于分界点两端的子串,这样一个分界点带来的不符合要求的子串就是: N u m S ( 1 ) + N u m S ( 2 ) − 1 Num{S(1)}+Num{S(2)}-1 NumS(1)+NumS(2)1 ,Num(.)是指的子串的数量,-1是减去AB或BA这种计算了两次的情况。因此,总的不符合要求的子串数量,只需要找出分界点及其两端的子串长度,按照如上公式累加即可。

代码
#include<bits/stdc++.h>
using namespace std;
typedef long long llong;
llong sum=0,ans=0,n=0;
// sum - XXXABXXXX(zuo->you , you->zuo)
struct barrier{
 int lcnt,rcnt;
}b[300099];
llong getSub(llong x){
 return x*(x-1)/2;
}
int main()
{
// freopen("in.txt","r",stdin);
 scanf("%lld",&n); string str="";
 cin>>str;
 int pt=0; //fenjie
 int acc=0;
 sum=(n*(n-1))/2;
 char x = str[0];
 for(int i=0;i<n;i++){
  if(str[i]==x) acc++;
  else {
   b[pt].lcnt=acc;
   if(pt>0) b[pt-1].rcnt=acc;
   acc=1;
   pt++;
   x=str[i];
  }
 }
 if(acc!=0){
  b[pt-1].rcnt=acc;
 }
 for(int i=0;i<pt;i++){
  sum-=b[i].lcnt+b[i].rcnt-1;//XXX(AB)XXXX cal 2
 }
 cout<<sum;
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值