CSP-J模拟赛四补题报告

日期:2023-10-03

学号:S12418

一:

总分数:40

T1【复读机(repeater)】:0

T2【小可的矛与盾(spearshield)】:40

T3【不合法字符串(illegality)】:0

T4【虚假的珂朵莉树(kodori)】:0

二、比赛过程

第一题低级错误

第二题不知道abs返回int

第三题时间超限

第四题和没写差不多(

讽刺的是,考试结束自己测的T1T2立马全100了

三、比赛分析

T1【复读机(repeater)】:
1、题目大意

有多组测试数据。

给定一个字符串,其中含有若干个数字,将数字之前的部分乘以数字后输出。

2、比赛中的思考

先读入数字,如果后面是别的字符就转,也可以当场转;

如果最后面没有数字,将该字符串后面接上最后的字符,输出。

很简单但是我写错了(

3、解题思路

同上。甚至连long long 都不用 直接暴力枚举就行

4、AC代码
 

#include<iostream>
#include<string>
#include<cstdio>
using namespace std;
int main(){
	int t;
	cin>>t;
	while(t--){
		int l;
		cin>>l;
		string a = "",b = "",c = "";
		int number = 0;
		cin>>a;
		for(int i = 0;i<l;i++){
			if(a[i]>='0'&&a[i]<='9'){
				number = number*10+(a[i]-'0');

			}
			else{
				if(number>1){
				b+=c;
				c = "";
				string s = b;
					for(int j = 1;j<number;j++){
						b+=s;
					}
					
				}
				number = 0;
				c+=a[i];
			}
			}
		if(number ==1) b+=c;
		else if(number>1){
			b+=c;
			string s = b;
			for(int j = 1;j<number;j++){ 
						b+=s;
			}
		}
		cout<<b<<endl;
	}
		return 0;
}

T2【小可的矛与盾(spearshield)】:
1、题目大意

n个人站一排 01串分别表示“当前人只能使用矛/盾”,且当前人的“力量” = 下标

让你找到一个点将这排人分两半,做到abs(前面,矛的总攻击力)-abs(后面,盾的总防御力)的值最小。

2、比赛中的思考

水。

太水了。

数据简单到离谱。

但是这题我还是没得满分。

为什么?我又没上过D2的课程我怎么知道abs返回值是int类型a.......

3、解题思路

先求出盾的总防御 再从前向后遍历字符串求出矛的总攻击(记得减去盾)最后取最小值即可

4、AC代码

#include<iostream>
#include<string>
#include<cmath>
#include<cstdio>
using namespace std;
long long n;
string s;
int main(){
cin>>n;
cin>>s;
s = "-" + s + "-";
long long w = 0,v = 0;
for(long long i = 0;i<n+1;i++){
	if (s[i] == '1'){
		v += i;
	}
}
long long res = v;
for(int i = 0;i<n+1;i++){
	if (s[i] == '0') w += i;
       
    if (s[i] == '1') v -= i;
        
    res = min(res, abs(w-v));
	
}
    
cout<<res;
return 0;
}

T3【不合法字符串(illegality)】:
1、题目大意

同上,有多组输入。

对于每一组数据:有n个字符串(可能是单个字符),ta们是“非法的”,现给定一个大字符串,这些“非法的”小字符串不能出现在大字符串中(对于长度>=2的非法字符串,在大字符串中出现一部分被认为是合法的。)

如果检测出来非法,用最少的*号替换掉。

最后输出经过替换的大字符串。

2、比赛中的思考

好好做了 但是没过

解法比较暴力 时间超了(但是为什么是0分?)

利用find函数,更改非法字符串最后一个字符。(字符越靠后,其他非法字符串含有这个字符的可能性越高)当然,代码很少,时间复杂度很高(O(n^3))

3、解题思路

最后一个字符的思路仍然有效。

方法如下:遍历过程中,查找以当前字符为结尾的“非法”字符串是否存在。(使用strcmp函数截取)

如果存在,则用 * 号替换掉;运用此方法,时间复杂度为O(n log n)

4、AC代码

T4【虚假的珂朵莉树(kodori)】:
1、题目大意

小可有一棵树,有 n 个节点,根节点为 1, 每个节点都有一个权值。
设每个节点与根节点距离是这个节点的深度。
小可会在这棵树上增加 m 条虚假边,任意一条虚假边不会和原来的树边或其他虚假边重合(增加的虚假边不影响节点深度)。
之后小可会进行 q 次操作:
操作1: 让结点 u 的权值增加 k ,并对与结点 u 相邻的结点中,深度比结点 k 小的结点重复操作1。 操作2:让结点 u 的权值增加 k ,并对与结点 u 相邻的结点中,深度比结点 u 大的结点重复操作2。
小可想知道,经过 q 次操作之后,所有的节点的权值是多少。

2、比赛中的思考

用链表建树的方法忘了,所以连暴力也没写出来(((

唉.....

(话说这个珂朵莉树是什么东西?)

3、解题思路

链表建珂朵莉树,通过空间换时间

每一次操作都立刻进行肯定是不行的,所以我们把所有的操作记录下来最后统一结算

深搜dfs开团,然后前缀和打辅助,最后状态表(操作1和操作2结算)打输出,结束战斗

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 M = 5000050;
const int N = 1000010;
vector<pr>g;
long long a[N],up[N],down[N];
int n,m,q,d[N];
int head[M],Next[M],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-1;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());//按照深度从小到大排,更新操作2应该增加的权值
    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的孩子,才进行操作2的更新
            //用前缀和更新要累加的权值
            if(d[y]>d[x]){
                down[y] = (down[y]+down[x])%p;
            }
        }
    }
    reverse(g.begin(),g.end());//按照深度从大到小排,更新操作1
    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];
            //如果y的深度<x,说明y是x的父亲
            
            if(d[y]<d[x]){
                up[y] = (up[y]+up[x])%p;
            }
        }
    }
    for(int i = 1;i<=n;i++){
        cout<<(down[i]+up[i]+a[i])%p<<" ";
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值