CSP-J复赛模拟四补题报告

S14754 赵廷赫

一,比赛情况

爆0。

二,补题报告

T1:

复读机(repeater)

时间限制:1秒        内存限制:256M

题目描述:

人类的本质是复读机。

小可喜欢在群里复读别人说过的话,这种人通常被称为复读机。现在小可想模拟复读机过程,过程如下:

现在给定一个长度为 n 的仅包含小写字母和数字的字符串,字母表示需要复读的消息,数字表示要复读的次数。

然而复读没有这么简单,小可想进行一个更复杂的复读模拟, 于是这个字符串中可能包含多个数字, 当多次出现数字时,例如 a5b2a5b2,我们从左到右解析这个字符串,a5a5 表示将 aa 复读 5 遍,即原字符串变 为 aaaaabaaaaab ,然后遇到数字 2 ,再将所有消息全部复读 2 遍,即 aaaaabaaaaab

题目解析:

模拟算法,模拟复读过程。

AC代码:

#include<bits/stdc++.h>

using namespace std;

int t,n;

string s;

char a[500005];

int main()

{

freopen("repeater.in","r",stdin);

freopen("repeater.out","w",stdout);

cin>>t;

while(t--)

{

int cnt=0;

cin>>n>>s;

for(int i=0;i<n;++i)

{

if(s[i]>='a'&&s[i]<='z')

{

cnt++;

a[cnt]=s[i];

}

if(s[i]>='1'&&s[i]<='9')

{

int sum=0;

int k=i;

while(s[k]>='0'&&s[k]<='9')

{

sum=sum*10+(s[k]-48);

k++;

}

int maxn=0;

for(int p=2;p<=sum;++p)

{

for(int i=1;i<=cnt;++i)

{                maxn=max(maxn,(p-1)*cnt+i);

a[(p-1)*cnt+i]=a[i];

}

}

cnt=max(cnt,maxn);

}

}

for(int i=1;i<=cnt;++i)

{

cout<<a[i];

}

cout<<"\n";

}

return 0;

}

T2:

题目描述

有n个小可战士站成一排,他们的编号从1到n,每个小可都有一个战斗力xi=i,但是小可们有不同的分工,有的充当队伍的矛,有的充当队伍的盾,矛的攻击力和盾的防御力和小可本身的战斗力相同。我们要将小可们分成两个阵营,编号 [1,pos] 为第一阵营,第一阵营中我们只考虑矛的攻击力总和w,编号[pos+1,n]为第二阵营,第二阵营中我们只考虑盾的防御力总和v,请问对于所有的 pos ,∣w−v∣ 的值最小,请问∣w−v∣ 最小为多少。

输入描述

第一行:输入一个正整数 n 。

第二行:输入一行长度为 n 的只含有 0 或 1 的字符串,如果字符串某一位是0,则表示小可充当队伍矛,否则为盾。

输出描述

输出一个整数答案

题目解析:用前缀和和后缀和,枚举最小值,判断最小的绝对值。

AC代码:

    #include<bits/stdc++.h>

#define ll long long

using namespace std;

ll n,a[100005],b[100005];

string s;

int main(){

    cin>>n>>s;

    s="*"+s;

    for(int i=1;i<=n;++i){

        if(s[i]=='1'){

            a[i]=a[i-1];

        }

        else{

            a[i]=a[i-1]+i;

        }

    }

    for(int i=n;i>=1;--i){

        if(s[i]=='1'){

            b[i]=b[i+1]+i;

        }

        else{

            b[i]=b[i+1];

        }

    }

    ll minn=min(a[n],b[1]);

    for(int i=1;i<=n;++i){

        ll k=abs(a[i]-b[i+1]);

        minn=min(minn,k);

    }

    cout<<minn;

    return 0;

}  

T3:                                                        

(illegality.cpp/c)

不合法字符串

3.1 问题描述

小可是一名小说审核员,他的工作是看小说,然后把小说中不合法字符串和谐掉。

现在给出若干个不合法的字符串 ,和一篇小说 ,小可需要把 中的不合法字符串用 * 和谐掉。当然小可是一个很聪明的审核员,他会用最少的 * 和谐字符串。

比如:

有三个不合法字符串: abc 、 ab 、 a 。 str=abcd

他会只和谐 a ,使得 str=*bcd ,这样小说中就没了不合法字符串。

请输出和谐之后的小说。

3.2 输入格式

第一行:输入一个整数 表示测试用例数。

对于每组测试样例:

第一行:输入一个正整数 n ,表示不合法字符串的数量。

接下来n行:每行输入一个字符串,表示不合法字符串。

接下来一行:输入一个字符串,表示小说。

3.3 输出格式

输出和谐之后的小说。

题目解析:

用枚举法,对每一位向前寻找,找到以这一位结尾的单词,则更改单词的最后一位。

AC代码:#include<bits/stdc++.h>

using namespace std;

int T,n,m;

string str[100000],tgt;

int main()

{

cin>>T;

while(T--){

cin>>m;

for(int i=1;i<=m;i++)

cin>>str[i];

cin>>tgt;

n=tgt.length();

tgt=' '+tgt;

for(int i=1;i<=n;i++){

for(int j=1;j<=m;j++){

if(i<str[j].length())

continue;

if(tgt.substr(i-str[j].length()+1,str[j].length())==str[j]){

tgt[i]='*';

}

}

}

for(int i=1;i<=n;i++)

cout<<tgt[i];

cout<<endl;

}

return 0;

}

T4:

虚假的珂朵莉树(kodori)

小可有一棵树,有 n 个节点,根节点为 1, 每个节点都有一个权值。

设每个节点与根节点距离是这个节点的深度。

小可会在这棵树上增加 m 条虚假边,任意一条虚假边不会和原来的树边或其他虚假边重合(增加的虚假边不影响节点深度)。

之后小可会进行 q 次操作:

操作1: 让结点 u 的权值增加 k ,并对与结点 u 相邻的结点中,深度比结点 k 小的结点重复操作1。 操作2:让结点 u 的权值增加 k ,并对与结点 u 相邻的结点中,深度比结点 u 大的结点重复操作2。

小可想知道,经过 q 次操作之后,所有的节点的权值是多少。

4.2 输入格式

第一行:输入三个整数 n、m、q,表示节点个数。虚假边条数,操作次数。

第二行:输入n个整数 ,表示节点的权值。

接下来 n-1 行:每行输入两个整数 u、v,表示树结构。

接下来 m 行:每行输入两个整数 u、v,表示虚假边。

接下来 q 行:每行输入三个整数 t、u、k。t表示操作类型、u表示要操作的节点,k表示权值增加k。

题目分析:

AC代码:

#include<bits/stdc++.h>

#define pr pair<int,int>

#define mk make_pair

using namespace std;

const long long p=1e9+7;

struct node{

int to,next;

}e[5000005];

vector<pr> g;

long long a[1000005],up[1000005],down[1000005];

int n,m,q,cnt,head[1000005],d[1000005];

void add(int u,int v){

e[++cnt].to=v;

e[cnt].next=head[u];

head[u]=cnt;

}

void dfs(int u,int fa){

g.push_back(mk(d[u],u));

for(int i=head[u];i;i=e[i].next){

int v=e[i].to;

if(v==fa) continue;

d[v]=d[u]+1;

dfs(v,u);

}

}

int main(){

cin>>n>>m>>q;

for(int i=1;i<=n;i++) cin>>a[i];

for(int i=1;i<=n-1;i++){

int u,v;

cin>>u>>v;

add(u,v);

}

dfs(1,1);

for(int i=1;i<=m;i++){

int u,v;

cin>>u>>v;

add(u,v);

add(v,u);

}

for(int i=1;i<=q;i++){

int pd,u,v;

cin>>pd>>u>>v;

if(pd==1) up[u]=(up[u]+v)%p;

else down[u]=(down[u]+v)%p;

}

sort(g.begin(),g.end());

int x=g[i].second;

for(int j=head[x];j;j=e[j].next){

int y=e[j].to;

if(d[y]>d[x]) down[y]=(down[y]+down[x])%p;

}

}

reverse(g.begin(),g.end());

int x=g[i].second;

for(int j=head[x];j;j=e[j].next){

int y=e[j].to;

if(d[y]<d[x]) up[y]=(up[y]+up[x])%p;

}

}

for(int i=1;i<=n;i++) cout<<(a[i]+up[i]+down[i])%p<<" ";

return 0;

}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值