NOIP2014-11-3模拟赛

时间:2022-12-25 23:20:07
NOIP2014-11-3模拟赛

字符串

题目描述

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

输入输出格式

输入格式:

输入文件名:string.in

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

输出格式:

输出文件名:string.out

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

输入输出样例

输入样例#1: 复制
adccdeed
输出样例#1: 复制
ad

说明

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

感冒病毒

题目描述

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

输入输出格式

输入格式:

输入文件:suspects.in

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

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

输出格式:

输出文件:suspects.out

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

输入输出样例

输入样例#1: 复制
100 4
2 1 10
5 10 13 11 12 14
2 0 1
2 9 2
输出样例#1: 复制
7

说明

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

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

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

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

弱点

题目描述

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

输入输出格式

输入格式:

输入文件:weakness.in

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

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

输出格式:

输入文件:weakness.out

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

输入输出样例

输入样例#1: 复制
4
10 8 3 1
输出样例#1: 复制
4

说明

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

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

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

滑动的窗户

题目描述

在一个包含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个整数,第一行表示窗户从左到右滑动过程中的最小值,第二行表示窗户从左到右滑动过程中的最大值。

输入输出样例

输入样例#1: 复制
8 3
1 3 -1 -3 5 3 6 7
输出样例#1: 复制
-1 -3 -3 -3 3 3
3 3 5 5 6 7

说明

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


T1:

暴力链表

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define MAXN 200005
using namespace std;
char s[MAXN];
int L[MAXN],R[MAXN];
int b[MAXN];
int n;
void del(int i){
b[i]=; b[R[i]]=;
R[L[i]]=R[R[i]];
L[R[R[i]]]=L[i];
if(L[i]&&R[L[i]]<=n&&s[L[i]]==s[R[L[i]]]){
del(L[i]);
}
}
int main()
{
// freopen("data.in","r",stdin);
gets(s+);
n=strlen(s+);
for(int i=;i<=n;i++){
L[i]=i-;
R[i]=i+;
}
for(int i=;i<=n;i=R[i]){
if(!b[i]&&!b[R[i]]&&s[i]==s[R[i]]){
del(i);
}
}
for(int i=;i<=n;i++){
if(!b[i]){
for(int j=i;j<=n;j=R[j]){
printf("%c",s[j]);
}
return ;
}
}
return ;
}

Code1


T2:

暴力搜索是可以过滴

 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<vector>
#define MAXM 502
#define MAXN 30002
using namespace std;
vector<int> G[MAXN];
vector<int> Q[MAXN];
int n,m;
int first[MAXM],Next[MAXM*MAXM*],to[MAXM*MAXM*],cnt;
//double edge
int p[MAXM][MAXM];
int num[MAXM];
int b[MAXM];
int ans=;
int used[MAXN];
void Add(int x,int y){
Next[++cnt]=first[x];first[x]=cnt;to[cnt]=y;
Next[++cnt]=first[y];first[y]=cnt;to[cnt]=x;
}
void dfs(int x){
b[x]=;
for(int i=;i<Q[x].size();i++){
used[Q[x][i]]=;
}
for(int e=first[x];e;e=Next[e]){
int y=to[e];
if(!b[y]){
dfs(y);
}
}
}
int main()
{
// freopen("data.in","r",stdin);
used[]=;
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
int l;
scanf("%d",&l);
for(int j=;j<=l;j++){
int t; scanf("%d",&t);
for(int k=;k<G[t].size();k++){
int x=G[t][k];
if(p[i][x]){
continue;
}
p[i][x]=p[x][i]=;
Add(i,x);
}
Q[i].push_back(t);
G[t].push_back(i);
}
}
for(int i=;i<G[].size();i++){
int x=G[][i];
if(!b[x])
dfs(x);
}
int ans=;
for(int i=;i<=n;i++){
ans+=used[i];
}
printf("%d\n",ans);
return ;
}

Code2-1

当然并查集更简单了

 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define MAXN 30005
using namespace std;
int fa[MAXN];
int size[MAXN];
int n,m;
int find(int x){
return ((x==fa[x])?x:fa[x]=find(fa[x]));
}
void lik(int x,int y){
x=find(x),y=find(y);
if(fa[x]!=y){
fa[x]=y;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
fa[i]=i;
}
for(int i=;i<=m;i++){
int p; scanf("%d",&p);
int t; scanf("%d",&t);
for(int i=;i<=p;i++){
int x;scanf("%d",&x);
lik(x,t);
}
}
for(int i=;i<=n;i++){
size[find(i)]++;
}
printf("%d",size[find()]);
return ;
}

Code2-2


T3:

三重逆序对,可以先处理以每个元素为末尾的二重逆序对数目

然后再做一次即可了

 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define MAXN 1000005
#define ll long long
using namespace std;
void add(ll d[],int k,ll x){
while(k>){
d[k]+=x;
k-=(k&-k);
}
}
ll sum(ll d[],int k){
ll ret=;
while(k<MAXN){
ret+=d[k];
k+=(k&-k);
}
return ret;
}
ll read(){
ll x=;char ch=getchar();
while(ch<''||ch>''){ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x;
}
ll a[MAXN];
ll b[MAXN];
ll d1[MAXN],d2[MAXN];
int n;
ll ans;
int main()
{
n=read();
for(int i=;i<=n;i++){
a[i]=read();
}
for(int i=;i<=n;i++){
b[i]=sum(d1,a[i]+);
add(d1,a[i],);
}
for(int i=;i<=n;i++){
ans+=sum(d2,a[i]+);
add(d2,a[i],b[i]);
}
printf("%lld\n",ans);
return ;
}

Code3


T4:

这题是单调队列的模版题

min则增队,max则减队

 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define MAXN 1000005
using namespace std;
int ql[MAXN],qr[MAXN],L=,R=;
int n,k;
int a[MAXN];
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;
}
void solve1(){
ql[]=a[];
qr[]=;
for(int i=;i<=n;i++){
while(L<=R&&ql[R]>=a[i]){
R--;
}
ql[++R]=a[i];
qr[R]=i;
if(i>=k){
printf("%d ",ql[L]);
if(i-k+>=qr[L])
L++;
}
}
}
void solve2(){
memset(ql,,sizeof(ql));
memset(qr,,sizeof(qr));
L=,R=;
ql[]=a[]; qr[]=;
for(int i=;i<=n;i++){
while(L<=R&&ql[R]<=a[i]){
R--;
}
ql[++R]=a[i];
qr[R]=i;
if(i>=k){
printf("%d ",ql[L]);
if(i-k+>=qr[L])
L++;
}
}
}
int main()
{
// freopen("0.in","r",stdin);
// freopen("p.out","w",stdout);
n=read(); k=read();
for(int i=;i<=n;i++){
a[i]=read();
}
solve1();
printf("\n");
solve2();
return ;
}

Code4