CSP-J模拟赛四李奕岑补题报告
日期:2023-10-03 周二
学号:S10228
文章目录
一:
总分数:170
T1 [复读机(repeater)]:100分
T2 [小可的矛与盾(spearshield)]:70分
T3 [不合法字符串(illegality)]:0分
T4 [虚假的珂朵莉树(kodori)]:0分
二:比赛过程
第一题比较顺利,经过几次调试,得到了满分。
第二题一看题就用前缀和,样例也对了,就是前缀和写错了,得了70分。
三四道题当时不会做,也不能骗分,就没有做。
三:题目分析
[复读机(repeater)]
1、题目大意
给定一个长度为n的仅包含小写字母和数字的字符串。
小写字母表示消息,数字表示复读次数。
字符串内可能包含多个数字,要从左到右解析字符串。
2、比赛中的思考
当时没想到用string,只想到了用char。
在输入的过程中判断是数字还是字母。
是字母就读入,是数字就复读。
最后加个特判并输出。
3、解题思路
我的想法是对的。
要注意复读是不能写x+=x。
因为这样会让每次复读的数据*2。
4、AC代码
#include<iostream>
#include<cstdio>
using namespace std;
char x,b[500005];
int main(){
int t,n;
cin>>t;
while(t--){
int cnt=0,q=0,flag=0;
cin>>n;
for(int i=1;i<=n;i++){
cin>>x;
if(x<='9'){
flag=1;
int l=x-'0';
q=q*10+l;
}
else if(flag==1){
flag=0;
if(q==0){
cnt=0;
}
int cnt1=cnt;
for(int j=2;j<=q;j++){
for(int k=1;k<=cnt1;k++){
cnt++;
b[cnt]=b[k];
}
}
q=0;
}
if(x>='a'){
cnt++;
b[cnt]=x;
}
}
if(flag==1){
if(q==0){
cnt=0;
}
int cnt1=cnt;
for(int j=2;j<=q;j++){
for(int k=1;k<=cnt1;k++){
cnt++;
b[cnt]=b[k];
}
}
}
for(int i=1;i<=cnt;i++){
cout<<b[i];
}
cout<<endl;
}
return 0;
}
[小可的矛与盾(spearshield)]
1、题目大意
n个小可战士站成一排,每个小可都有一个战斗力i。
小可们有不同的分工,有的充当矛,有的充当盾。
盾是0,矛是1。
矛的攻击力和盾的防御力与小可本身的战斗力相同。
小可们被分成两个阵营,一个是1到pos,是矛阵营,
一个是pos+1到n,是盾阵营。
求矛阵营战斗力减盾阵营战斗力的绝对值最小的pos。
2、比赛中的思考
最开始是从前往后记录矛的战力和,从后往前记录盾的战力和。
最后算出pos比较大小输出。
3、解题思路
这道题巨水。
这道题要用前缀和,用前缀和算出矛和盾的战力值,而不是像我一样。
4、AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
char x[100005];
long long a[100005],b[100005];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>x[i];
if(x[i]=='0'){
a[i]=a[i-1]+i;
b[i]=b[i-1];
}
else{
b[i]=b[i-1]+i;
a[i]=a[i-1];
}
}
long long minn=5190909090;
for(int i=1;i<=n;i++){
minn=min(minn,abs(a[i-1]-(b[n]-b[i-1])));
}
cout<<minn;
return 0;
}
[不合法字符串(illegality)]
1、题目大意
给出若干个不合法的字符串s[i]和一篇小说str,
需要把str中的不合法字符用
∗
*
∗和谐掉。
要用尽量少的
∗
*
∗。
2、比赛中的思考
看懂了但是不会做。string的操作都忘了。
3、解题思路
在和谐字符的时候,应该把单词的最后一个和谐能保证最优。
判断时先枚举小说的每一个字符,
再枚举每一个单词是否能和谐掉这个字符。
最后输出。
4、AC代码
#include<iostream>
#include<string>
using namespace std;
string s[12],ss;
int main(){
int t,n;
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++){
cin>>s[i];
}
cin>>ss;
int m=(int)ss.length();
ss=" "+ss;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(i<s[j].length()){
continue;
}
if(ss.substr(i-s[j].length()+1,s[j].length())==s[j]){
ss[i]='*';
}
}
}
for(int i=1;i<=m;i++){
cout<<ss[i];
}
cout<<endl;
}
return 0;
}
[虚假的珂朵莉树(kodori)]
1、题目大意
一棵树,有n个节点,根节点为1,每个节点都有一个权值。
在这棵树上增加m条虚假边(增加的虚假边不会影响节点深度)。
之后进行q次操作。
操作1:让结点 u 的权值增加 k ,并对与结点 u 相邻的结点中,深度比结点 k 小的结点重复操作1。
操作2:让结点 u 的权值增加 k ,并对与结点 u 相邻的结点中,深度比结点 u 大的结点重复操作2。
求经过q次操作后所有节点的权值。
2、比赛中的思考
样例都有点没看懂。
3、解题思路
在输入真实边之后立刻深搜确定每一个节点的深度,
然后输入虚假边。
用延迟更新的方式计算出操作一和操作二应该增加的权值,
最后判断条件更新。
最后输出。
4、AC代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#define pr pair<int,int>
#define mk make_pair
using namespace std;
const long long p=1e9+7;
const int N=1000010;
const int M=10*N;
vector<pr>g;
long long a[N],up[N],down[N];
int n,m,q,d[N];
int head[N],Next[N],ver[M],tot=-1;
void ADD(int x,int y){
ver[++tot]=y;
Next[tot]=head[x];
head[x]=tot;
}
void dfs(int x,int fa){//记录并更新每一个节点深度
g.push_back(mk(d[x],x));//将节点及其深度放入数组
for(int i=head[x];~i;i=Next[i]){
//遍历u的邻接表更新深度
int y=ver[i];
if(y==fa){
continue;
}
d[y]=d[x]+1;//计算深度
dfs(y,x);
}
}
int main(){
memset(head,-1,sizeof(head));
cin>>n>>m>>q;
for(int i=1;i<=n;i++){
cin>>a[i];//输入点权
}
for(int i=1;i<n;i++){//输入实际边
int x,y;
cin>>x>>y;
ADD(x,y);
ADD(y,x);
}
dfs(1,1);
for(int i=1;i<=m;i++){//输入虚拟边
int x,y;
cin>>x>>y;
ADD(x,y);
ADD(y,x);
}
for(int i=1;i<=q;i++){
int op,u,v;
cin>>op>>u>>v;
if(op==1){//延迟更新,记录深度比u小的应该增加的权值
up[u]=(up[u]+v)%p;
}
else{//记录深度比u大的
down[u]=(down[u]+v)%p;
}
}
sort(g.begin(),g.end());//按照深度从小到大排,更新操作二应该增加的权值
for(int i=0;i<g.size();i++){
int x=g[i].second;
for(int j=head[x];~j;j=Next[j]){
//对于每一个节点,遍历它的邻接表
//找到x的邻接点
int y=ver[j];
//如果y深度大于x,说明y是x的孩子,才进行操作二的更新
//用前缀和更新要累加的权值
if(d[y]>d[x]){
down[y]=(down[y]+down[x])%p;
}
}
}
reverse(g.begin(),g.end());//按照深度从大到小排序,更新操作一增加的权值
for(int i=0;i<g.size();i++){
int x=g[i].second;//x是这个点的编号
for(int j=head[x];~j;j=Next[j]){
int y=ver[j];//找x的邻接点
//如果y的深度小于x,说明y是x的父亲,才进行操作1的更新
//同上
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;
}