字符串

string.pas/c/cpp

1S/256MB

【题目描述】

现在给一个字符串,你要做的就是当这个字符串中存在两个挨着的字符是相同的时就将这两个字符消除。需要注意的是,当把这两个字符消除后,可能又产生一对新的挨着的字符是相同的。比如,初始的字符串是abcddc,dd是两个挨着的相同的字符,当把"dd"消除后,得到的字符串是abcc,这时cc又是两个挨着的相同的字符,所以又应该把cc消除。重复以上操作直到剩下的串中不存在两个挨着的字符是相同的为止,输出最终剩下的串。另外需要注意的是,多对相同字符的消除顺序是不会对答案产生影响的,可以证明最后他们都会达到唯一的结果,比如,对于初始字符串adccdeed,无论是adccdeed->addeed->aeed->ad还是adccdeed->adccdd->adcc->ad,最终的输出结果都是ad。

【输入】

输入文件名:string.in

输入的第一行,包含一个字符串,为初始字符串,所有的字符均为小写字母。

【输出】

输出文件名:string.out

输出为一行,包含一个字符串,为执行多次消除操作后最终剩下的字符串。

【输入样例】

adccdeed

【输出样例】

ad

【数据范围】

对于100%的数据,字符串的长度在1到200000之间。

/*
操作很麻烦,写了一个大模拟,用双向链表维护删除操作,用时1h,总觉得有超时的风险
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 200010
using namespace std;
int a[maxn],fir=,len,now;
bool vis[maxn];
struct node{
int pre,to;
}q[maxn];
char s[maxn];
bool check(){
while(vis[fir]==)fir++;
int before=;
now=fir;
for(;now<=len;now=q[now].to){
if(a[now]==a[before])return ;
before=now;
}
return ;
}
int main(){
//freopen("Cola.txt","r",stdin);
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
scanf("%s",s+);
len=strlen(s+);
for(int i=;i<=len;i++){
a[i]=s[i]-'a';
q[i].pre=i-;q[i].to=i+;
}
a[]=-;
while(){
if(check()){
while(vis[fir]==)fir++;
while(fir<=len){
printf("%c",a[fir]+'a');
fir=q[fir].to;
}
break;
}
while(vis[fir]==)fir++;
int before=;
now=fir;
int flag=,cnt=,head=fir,headto;
for(;now<=len;now=q[now].to){
if(a[now]==a[before]){
if(flag==)head=before,headto=now;
flag=;
vis[now]=;vis[before]=,cnt++;
q[q[now].to].pre=q[before].pre;
q[now].pre=q[before].pre;
q[q[before].pre].to=q[now].to;
q[before].to=q[now].to;
break;
}
before=now;
}
}
}

60分 双向链表+模拟 TLE

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define pa pair<int,int>
#define inf (1LL<<60)
#define mod 1000000007
#define ll long long
using namespace std;
int read(){
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
char a[];
int n;
int l[],r[];
void del(int x){
int L=l[x],R=r[x];
r[L]=R;l[R]=L;
}
int main(){
//freopen("string.in","r",stdin);
//freopen("string.out","w",stdout);
scanf("%s",a+);n=strlen(a+);
for(int i=;i<n;i++)r[i]=i+;
for(int i=;i<=n;i++)l[i]=i-;
for(int now=r[];now;now=r[now]){
while(now&&a[now]==a[l[now]]){
int t=r[now];
del(l[now]);del(now);
now=t;
}
}
for(int now=r[];now;now=r[now])
printf("%c",a[now]);
puts("");
return ;
}

100分 栈+链表模拟

感冒病毒

suspects.pas/c/cpp

1S/256MB

【题目描述】

一种感冒病毒正在学校里传播,这所学校有n个学生,m个学生社团,每个学生可能参加了多个社团,因为同一个社团的学生交流较多,所以如果一个学生感染上感冒病毒,那么他所在的社团里的所有学生都会感染上感冒病毒,现在已知0号学生感染上感冒病毒,问现在有多少人会感染上感冒病毒。

【输入】

输入文件:suspects.in

输入的第一行是两个整数n和m,表示学生的数目和社团的数目,学生的编号为0到n-1。

接下来m行,每行首先是一个数ki,表示这个社团有ki个人,接下来ki个整数,表示这个社团里每个学生的编号aij。

【输出】

输出文件:suspects.out

输出为一行,包含一个整数。表示感染感冒病毒的人数。

【输入样例】

100 4

2 1 10

5 10 13 11 12 14

2 0 1

2 9 2

【输出样例】

7

【数据范围】

对于100%的数据,3<=n<=30000

对于100%的数据,3<=m<=500

对于100%的数据,1<=ki<=n

对于100%的数据,0<=aij<n。

/*
一眼题,一看就是并查集,就写出来了,用时10分钟
*/
#include<iostream>
#include<cstdio>
#define maxn 30010
using namespace std;
int n,m,fa[maxn];
int find(int x){
if(fa[x]==x)return fa[x];
return fa[x]=find(fa[x]);
}
void connect(int a,int b){
int f1=find(a);
int f2=find(b);
if(f1==f2)return;
fa[f1]=f2;
}
int main(){
freopen("suspects.in","r",stdin);
freopen("suspects.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)fa[i]=i;
int x,y,z;
for(int i=;i<=m;i++){
scanf("%d",&x);
if(x>)scanf("%d",&y),y++;
if(x>){
for(int j=;j<=x;j++){
scanf("%d",&z);z++;
connect(y,z);
}
}
}
int ans=;
for(int i=;i<=n;i++)
if(find(i)==find())ans++;
printf("%d",ans);
}

100分 并查集

弱点

weakness.pas/c/cpp

2S/256MB

【题目描述】

一队勇士正在向你进攻,每名勇士都有一个战斗值ai。但是这队勇士却有一个致命弱点,如果存在i<j<k使得ai>aj>ak,则会影响他们整体的战斗力。我们将这样的一组(i,j,k)称为这队勇士的一个弱点。请求出这队勇士的弱点数目。

【输入】

输入文件:weakness.in

输入的第一行是一个整数n,表示勇士的数目。

接下来一行包括n个整数,表示每个勇士的战斗值ai。

【输出】

输入文件:weakness.out

输出为一行,包含一个整数。表示这队勇士的弱点数目。

【输入样例】

4

10 8 3 1

【输出样例】

4

【数据范围】

对于30%的数据,3<=n<=100

对于100%的数据,3<=n<=1000000

对于100%的数据,1<=ai<=1000000,每个ai均不相同

#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 1000010
int n,a[maxn],ans;
int main(){
freopen("weakness.in","r",stdin);
freopen("weakness.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
for(int i=;i<=n;i++){
for(int j=i+;j<=n;j++){
for(int k=j+;k<=n;k++){
if(a[i]>a[j]&&a[j]>a[k])ans++;
}
}
}
cout<<ans;
return ;
}

30分 暴力

/*
枚举i的话,要求左边比它大的个数和右边比它小的
*/
#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 1000001
int n,tr[][maxn],a[maxn];
long long query(int x,int pos){
long long res=;
while(pos){
res+=tr[x][pos];
pos-=pos&(-pos);
}
return res;
}
void add(int x,int pos,int d){
while(pos<=maxn){
tr[x][pos]+=d;
pos+=pos&(-pos);
}
}
int main(){
freopen("weakness.in","r",stdin);
freopen("weakness.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
add(,a[i],);
}
long long ans=;
for(int i=;i<=n;i++){
add(,a[i],-);
ans+=(query(,)-query(,a[i]))*(query(,a[i]-));
add(,a[i],);
}
cout<<ans;
}

100分 树状数组

滑动的窗户

window.pas/c/cpp

3S/256MB

【题目描述】

在一个包含n个元素的数组上,有一个长度为k的窗户在从左向右滑动。窗户每滑动到一个位置,我们都可以看到k个元素在窗户中。如下的例子所示,假设数组为 [1 3 -1 -3 5 3 6 7],而k等于3:

窗户位置

最小值

最大值

[1  3  -1] -3  5  3  6  7

-1

3

1 [3  -1  -3] 5  3  6  7

-3

3

1  3 [-1  -3  5] 3  6  7

-3

5

1  3  -1 [-3  5  3] 6  7

-3

5

1  3  -1  -3 [5  3  6] 7

3

6

1  3  -1  -3  5 [3  6  7]

3

7

对于窗户滑动过的每个位置,请给出窗户内k个元素的最小值和最大值。

【输入】

输入文件:window.in

输入的第一行包括两个整数n,k,n表示数组的长度,k表示窗户的长度。

接下来一行包括n个整数,表示这个n个元素的数组。

【输出】

输出文件:window.out

输出包含两行,每行包括n-k+1个整数,第一行表示窗户从左到右滑动过程中的最小值,第二行表示窗户从左到右滑动过程中的最大值。

【输入样例】

8 3

1 3 -1 -3 5 3 6 7

【输出样例】

-1 -3 -3 -3 3 3

3 3 5 5 6 7

【数据范围】

对于100%的数据,3<=n<=1000000,1<=k<=n,数组中的每个元素均在int范围内

#include<iostream>
#include<cstdio>
using namespace std;
#define maxn 1000010
int n,k,qmax[maxn],qmin[maxn],a[maxn],h1=,h2=,t1,t2;
int ans1[maxn],ans2[maxn];
int main(){
//freopen("Cola.txt","r",stdin);
freopen("window.in","r",stdin);
freopen("window.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
for(int i=;i<k;i++){
while(h1<=t1&&a[qmax[t1]]<=a[i])t1--;
qmax[++t1]=i;
while(h2<=t2&&a[qmin[t2]]>=a[i])t2--;
qmin[++t2]=i;
}
for(int i=k;i<=n;i++){
while(h1<=t1&&qmax[h1]<=i-k)h1++;
while(h1<=t1&&a[qmax[t1]]<=a[i])t1--;
qmax[++t1]=i;ans1[i]=a[qmax[h1]];
while(h2<=t2&&qmin[h2]<=i-k)h2++;
while(h2<=t2&&a[qmin[t2]]>=a[i])t2--;
qmin[++t2]=i;ans2[i]=a[qmin[h2]];
}
for(int i=k;i<=n;i++)printf("%d ",ans2[i]);printf("\n");
for(int i=k;i<=n;i++)printf("%d ",ans1[i]);
fclose(stdin);fclose(stdout);
return ;
}

100分 单调队列

最新文章

  1. 【转】理解 PHP 依赖注入 | Laravel IoC容器
  2. 关于javascript中this的那点事
  3. grunt自动化构建工具
  4. leetcode Linked List Cycle
  5. XML实例入门2
  6. 使用python将mysql数据库的数据转换为json数据
  7. HttpServlet源码分析
  8. centos7安装部署gitlab服务器
  9. java课程之团队开发冲刺阶段1.6
  10. Hbase 元数据一致性检查(转)
  11. GetLastError 错误返回码
  12. codeforces 803D Magazine Ad(二分+贪心)
  13. GitHub &amp; OAuth 2.0 &amp; JWT
  14. 1301 邻值查找(set 平衡树 | 链表)
  15. 大整数加减运算的C语言实现
  16. python中的多进程与多线程(二)
  17. SVN提交的动作解释
  18. 〖Linux〗Qt5.2.0+gsoap开发Android的NDK程序遇到错误的解决
  19. 20145209 2016-2017-2 《Java程序设计》第3周学习总结
  20. php学习(二)——html + css

热门文章

  1. js和jquery 两种写法 鼠标经过图片切换背景效果
  2. 关于VS中包含库、附加包含库、
  3. ubuntu命令行卸载软件
  4. Asp.Net页面生命周期【转载,地址:http://www.cnblogs.com/xhwy/archive/2012/05/20/2510178.html】
  5. 11g RAC 如何备份OCR,利用备份恢复OCR,ocrdump
  6. Azure CLI下载Azure Storage Container内的所有文件
  7. POJ2080:Calendar(计算日期)
  8. 【转】 Pro Android学习笔记(三二):Menu(3):Context菜单
  9. pycharm安装 package报错:module &#39;pip&#39; has no attribute &#39;main&#39;
  10. uboot启动参数设置分类及方法