目录
2. 数据范围:
一.比赛概况:
比赛共4题,250/400,T1~T4:100/90/20/40
T2没考虑左端点,-10,气死我了。
T3思路有了,和老师讲的一样,我却只把它放在暴力里(一个if,分开了我与AC)
二.比赛过程:
T1是一道简单的字符串操作的题,秒了。
T2是一道是一道模拟,但数据过大,要前缀和优化,秒了。
(T1+T2才用了20min,导致被T3T4虐了2h+)
T3又是一道字符串的题(今天捅字符串老窝了???),像是一个字典树(J组有字典树?),但写不出来,只能暴力。
T4是一道图论(J组有珂朵莉树???)。只能暴力。
(今天的暴力竟然都拿到了,题比前两天简单了)
三.题解报告:
【T1:复读机】
(100分)
1. 题意:
给定一个长度为n的仅包含小写字母和数字的字符串,字母表示需要复读的消息,数字表示要复读的次数。这个字符串中可能包含多个数字, 当多次出现数字时,如a5b2,从左到右解析,a5表示将a复读5遍,原字符串变为aaaaab,遇到数字 2 ,再全部复读 2 遍,即aaaaabaaaaab 。
2. 数据范围:
30%的数据下:所有数字独立出现,即数字最多只有一位。
100%的数据下:,最终的字符串长度
3. 赛时本题做题想法/题解:
直接模拟,p来存之前的字符串,sp来存新的字符串,把新串字母加到sp中,数字存到x中,最后把x个sp赋值到p上。
4. AC代码:
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int t,n;
string a;
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
cin>>a;
string p="";
for(int i=0;i<a.size();){
string sp=p;
while(a[i]>='a'&&a[i]<='z') sp=sp+a[i++];
int x=0;
while(a[i]>='0'&&a[i]<='9') x=x*10+(a[i++]-'0');
p=sp;
for(int j=2;j<=x;j++) p+=sp;
}
cout<<p<<endl;
}
return 0;
}
【T2:小可的矛与盾】
(90分,已补题)
1. 题意:
有n个人站成一排(1到n),每人都有一个战斗力xi=i,有的当矛,有的当盾,矛的攻击力和盾的防御力和本身的战斗力相同。将他们分成两个阵营,为第一阵营,只考虑矛的攻击力总和w;为第二阵营,只考虑盾的防御力总和v.求对于所有的,的值最小,求最小为多少。
2. 数据范围:
20%的数据下:
40%的数据下:
100%的数据下:
3. 赛时本题做题想法:
是一道模拟题,枚举1-n+1,把v和w算出来,取最小值。但数据过大,要前缀和优化。
4. 题解:
因为,所以枚举1-n+1,因为,所以用前缀和优化。
5. AC代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<cmath>
using namespace std;
int n;
string s;
long long m[100005],d[100005],ans=1e18;
int main(){
cin>>n;
cin>>s;
s=" "+s;
for(int i=1;i<s.size();i++){
m[i]=m[i-1];
d[i]=d[i-1];
if(s[i]=='0') m[i]+=i;
if(s[i]=='1') d[i]+=i;
}
for(int i=0;i<=n;i++){//考试是i=1,落了一个左端点,-10
long long w=m[i],v=d[n]-d[i];
long long p=(w>v)?(w-v):(v-w);
ans=min(ans,p);
}
cout<<ans;
return 0;
}
【T3:不合法字符串】
(20分,已补题)
1. 题意:
给出若干个不合法的字符串s[i],和一篇小说str ,需要把str中的不合法字符串用 *
和谐掉。当用最少的 *
和谐字符串,输出和谐之后的小说。
2. 数据范围:
20%的数据下:
50%的数据下:小说长度
100%的数据下:,,每个不合法字符串长度,小说长度
3. 赛时本题做题想法:
没思路,看暴力,应该是删不合法字符串的最后一位,写上了。
4. 题解:
对于输入的字符串来说,和谐最后的字符价值远比其他位置要大。(所以当时的思路对了,把外面的if去了就行了。)所以枚举str,再枚举s[i],对字符串每一位往前寻找,若是找到任意一个以这一位结尾的单词就删最后一位。
5. AC代码:
#include<iostream>
#include<cstdio>
using namespace std;
int t,n,p=0;
string a,s[15];
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++) cin>>s[i];
cin>>a;
for(int i=0;i<a.size();i++){
for(int j=1;j<=n;j++){
if(i<s[j].size()-1) continue;
if(a.substr(i-s[j].size()+1,s[j].size())==s[j]) a[i]='*';
}
}
cout<<a<<endl;
}
return 0;
}
【T4:虚假的珂朵莉树】
(40分,已补题)
1. 题意:
有一颗n个节点的树,根节点为1,有点权。设每个节点与根节点距离是这个节点的深度。小可会在这棵树上增加m条虚假边,无重边(增加的虚假边不影响节点深度)。之后小可会进行 q 次操作:1:让结点u的权值增加k,与结点 u 相邻的深度比结点 u 小的结点中重复操作1。2:让结点u的权值增加k,与结点u相邻的深度比结点 u 大的结点中重复操作2。求经过q次操作之后,所有的节点的权值是多少。(由于权值可能很大,请将权值对进行取模。)
2. 数据范围:
20%的数据下:
另有20%的数据下:,且只有操作2 。
100%的数据下:
3. 赛时本题做题想法:
又到图论了,我又兴奋了。看题,可以模拟,就按模拟来写。
又发现,可以改进。把每一次的结果存起来,到最后再进行模拟。
在考试时,我只能想到这。但这就是优化的极限吗?
4. 题解:
不!
我们已经把结果都存起来,但模拟太耗时间。我们可以分类讨论。
对于1,只能从下往上,所以我们把深度排序。按从下到上进行操作,只需要一边就行。
对于2,同理,从上到下。
5. AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define mod 1000000007
#define N 1000005
#define mp make_pair
#define f first
#define s second
using namespace std;
int n,m,q,deep[N],V[N],fst[N],nxt[N],idx=0;
long long a[N],wup[N],wdown[N];
vector<pair<int,int> > ve;
void add(int a,int b){
V[idx]=b;
nxt[idx]=fst[a];
fst[a]=idx++;
}
void dfs(int u,int fa){
ve.push_back(mp(deep[u],u));
for(int i=fst[u];i!=-1;i=nxt[i]){
int v=V[i];
if(v==fa) continue;
deep[v]=deep[u]+1;
dfs(v,u);
}
}
int main(){
memset(fst,-1,sizeof(fst));
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1,1);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
while(q--){
int t,u;
long long k;
scanf("%d%d%lld",&t,&u,&k);
if(t==1) wup[u]=(wup[u]+k)%mod;
else wdown[u]=(wdown[u]+k)%mod;
}
sort(ve.begin(),ve.end());
for(int i=0;i<ve.size();i++){
int x=ve[i].s;
for(int j=fst[x];j!=-1;j=nxt[j]){
int y=V[j];
if(deep[y]>deep[x]) wdown[y]=(wdown[y]+wdown[x])%mod;
}
}
reverse(ve.begin(),ve.end());
for(int i=0;i<ve.size();i++){
int x=ve[i].s;
for(int j=fst[x];j!=-1;j=nxt[j]){
int y=V[j];
if(deep[y]<deep[x]) wup[y]=(wup[y]+wup[x])%mod;
}
}
for(int i=1;i<=n;i++) printf("%lld ",(a[i]+wdown[i]+wup[i])%mod);
return 0;
}
四.赛后总结:
今天是目前分最高的一天,但还是有一些失误的点。1.没把数据看全(T2) 2.不够自信(T3) 3.把思路伸下去(T4)
(听说明天题更简单)
日期:2023年10月04日星期三
姓名:董峻熙