csp-s2023-zong-jie
CSP-S2023总结
posted on 2023-10-24 08:16:22 | under 总结 | source
day-
忘了。
考了好几场牛客模拟。
gm说只有考好才能参加noip,并让我们早点休息。
所以到家10:40就睡了。
day0
睡到10:30,起床吃饭看电视。
按照gm的要求,从12:00午睡到13:05。
13:15到了,有个不认识的人不让进,在走廊看 Cindy 玩手机。
四处游荡,发现了正在吃饭的铁锹。
gm让我们到2楼,听其他人讲J组的题。
感觉不难。
14:30开始看题。
0~10min,发现T1很简单,用bitset跑过去了。
10~15min,看其他题,T2有区间dp的想法,但是明显过不了2e6的数据。T3讲的好像是去年复习CSP时我中午颓废的时候见过的东西,仔细看了一下,发现就是,一模一样。T4看起来很难,但是几个性质有点意思。
15~?min,把T2
?~80min,T3打完了,一遍过所有样例,感觉样例很水,不太放心,但没办法。
80~[120,140]min,看看T4,随便打了一点部分分,估计得分45,感觉295的成绩差不多了。
[120,140]min,然后发现T2
?~210min,决定搞T2。
我们发现如果一个区间可消除,那么一定可以描述为从头到尾一次入栈,与栈顶相同就弹栈,最后栈为空,打出
进行优化,发现可以考虑
搞了一个字典树,调了半天,比T3模拟还久。
但是搞出来了,2e6跑得飞快。
210~240min,T2也过了,想T4,发现完全不会,摆了。写了一些奇奇怪怪的东西,后来被骂了。
出来后进行讨论,发现有一堆人会T4,他们说到二分答案,但是我还不会,尴尬。
经过交流,发现还有一堆人T2打的 dp,一堆人没过模拟。感觉还行。
出来路上,yyn一边走一边哭,他说他T1一直没看懂,他可能废了。于是安慰了他一路。
看得出来,旁边的xhm也想哭。
回家后,先把abc的报名取消,免得掉分。
然后玩,看估分。
发现大概30min打的T4没分,估分直接从340+掉到300。
然后发现其实我这个成绩在机房还行。
听说不同地方的数据差别有点大,都测了,怎么都是300,为什么不加分?
询问了一下lay奇人大赏的进度。
“本来不想做的,但是既然你问了,我就可以把whk放一放了。”
这是她的回复。
day+
gm要求我们补题,写总结,所以有了这个。
发现成绩还是没有波动,生气。
CQ的一等线拉了其他地方一个三等线。。。
题目本身
T1
简单,每个串81种情况,搞个bitset随便过。
#include <bits/stdc++.h>
using namespace std;
int read(){
int x=0;char c=getchar();
while(c>'9'||c<'0')c=getchar();
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return x;
}
int n,a[10];
bitset<100000>F[10];
signed main()
{
// freopen("lock.in","r",stdin);
// freopen("lock.out","w",stdout);
n=read();
F[0].set();
for(int t=1;t<=n;t++){
for(int i=1;i<=5;i++)a[i]=read();
for(int i=1;i<=5;i++){
int las=a[i];
for(int j=0;j<=9;j++){
if(j!=las){
a[i]=j;
int x=0;
for(int k=1;k<=5;k++)x=x*10+a[k];
F[t][x]=1;
}
}
a[i]=las;
}
for(int i=1;i<=4;i++){
int A=a[i],B=a[i+1];
for(int j=1;j<=9;j++){
a[i]=(a[i]+1)%10;
a[i+1]=(a[i+1]+1)%10;
int x=0;
for(int k=1;k<=5;k++)x=x*10+a[k];
F[t][x]=1;
}
a[i]=A;
a[i+1]=B;
}
F[0]&=F[t];
}
printf("%d",(int)F[0].count());
return 0;
}
T2
我们发现,对于现在的栈,如果要加入
树就会变成这样。由于不可能出现连续的相同字母,所以我们只需要把
字典树轻松实现。
#include<bits/stdc++.h>
using namespace std;
int read(){
int x=0;char c=getchar();
while(c>'9'||c<'0')c=getchar();
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return x;
}
int n;
long long ans;
char s[2000005];
int cnt,Root;
struct Node{
int ch[26];
long long val;
}c[4000005];
int New(long long sum){
cnt++;
c[cnt].val=sum;
for(int i=0;i<26;i++)c[cnt].ch[i]=0;
return cnt;
}
int Get(int q,int id){
if(c[q].ch[id])return c[q].ch[id];
else return c[q].ch[id]=New(0);
}
void Add(int &q,long long x){
if(!q)q=New(x);
else c[q].val+=x;
}
void Merge(int q1,int q2){
c[q1].val+=c[q2].val;
for(int i=0;i<26;i++){
if(!c[q1].ch[i]||!c[q2].ch[i]){
c[q1].ch[i]=c[q1].ch[i]+c[q2].ch[i];
}
else{
Merge(c[q1].ch[i],c[q2].ch[i]);
}
}
}
signed main()
{
n=read();
scanf("%s",s+1);
Root=1;
cnt=1;
c[Root].val=1;
for(int i=1;i<=n;i++){
int Ro=Get(Root,s[i]-'a');
c[Root].ch[s[i]-'a']=0;
ans+=c[Ro].val;
int id=Get(Ro,s[i]-'a');
Merge(id,Root);
c[Ro].val++;
Root=Ro;
}
printf("%lld",ans);
return 0;
}
不算简单,但也不是太难。
T3
无他,按题意搞就可以了。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int read(){
int x=0;char c=getchar();
while(c>'9'||c<'0')c=getchar();
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return x;
}
int n,tot;
struct Str{
string name;
int a,siz;
int sum;
int o[105],w[105];
string op[105];
int id[105];
}str[155];
map<string,int>Pos;
int o[105],num,Lei[105];
string Nam[105];
map<string,int>Id;
string Get(int id,int abbr){
if(id<=4)return "";
for(int i=1;i<=str[id].sum;i++){
if(str[id].o[i]<=abbr&&abbr<str[id].o[i]+str[id].w[i]){
return "."+str[id].op[i]+Get(str[id].id[i],abbr-str[id].o[i]);
}
}
return "####";
}
signed main()
{str[1].name="byte";str[1].a=1,str[1].siz=1;str[1].sum=1;str[1].o[1]=0;
str[2].name="short";str[2].a=2,str[2].siz=2;str[2].sum=1;str[2].o[1]=0;
str[3].name="int";str[3].a=4,str[3].siz=4;str[3].sum=1;str[3].o[1]=0;
str[4].name="long";str[4].a=8,str[4].siz=8;str[4].sum=1;str[4].o[1]=0;
tot=4;
Pos["byte"]=1;Pos["short"]=2;Pos["int"]=3;Pos["long"]=4;
n=read();
int las=0;
while(n--){
int op=read();
if(op==1){
string t;
cin>>t;
int s=read();
Pos[t]=++tot;
str[tot].name=t;
str[tot].sum=s;
for(int i=1;i<=s;i++){
string S,nam;
cin>>S>>nam;
int ID;
str[tot].id[i]=ID=Pos[S];
str[tot].op[i]=nam;
str[tot].w[i]=str[ID].siz;
str[tot].o[i]=((str[tot].o[i-1]+str[tot].w[i-1]+str[ID].a-1)/str[ID].a)*str[ID].a;
str[tot].a=max(str[tot].a,str[ID].a);
}
str[tot].siz=((str[tot].o[s]+str[str[tot].id[s]].siz+str[tot].a-1)/str[tot].a)*str[tot].a;
printf("%lld %lld\n",str[tot].siz,str[tot].a);
}
else if(op==2){
string Cal,nam;
cin>>Cal>>nam;
num++;
Id[nam]=num;
int id=Pos[Cal];
Lei[num]=id;
Nam[num]=nam;
o[num]=(las+str[id].a-1)/str[id].a*str[id].a;
las=o[num]+str[id].siz;
printf("%lld\n",o[num]);
}
else if(op==3){
string s;
cin>>s;
int len=s.length();
int Pos=0;
string t="";
int now=0;
for(int i=0;i<len;i++){
if(s[i]=='.'){
if(!now){
int id=Id[t];
Pos+=o[id];
now=Lei[id];
}
else{
for(int i=1;i<=str[now].sum;i++){
if(str[now].op[i]==t){
Pos+=str[now].o[i];
now=str[now].id[i];
break;
}
}
}
t="";
}
else t+=s[i];
}
if(!now){
int id=Id[t];
Pos+=o[id];
now=Lei[id];
}
else{
for(int i=1;i<=str[now].sum;i++){
if(str[now].op[i]==t){
Pos+=str[now].o[i];
now=str[now].id[i];
break;
}
}
}
printf("%lld\n",Pos);
}
else if(op==4){
int abbr=read();
bool F=0;
string ans="";
for(int i=1;i<=num;i++){
if(o[i]<=abbr&&o[i]+str[Lei[i]].siz>abbr){
ans+=Nam[i];
ans+=Get(Lei[i],abbr-o[i]);
F=1;
break;
}
}
int Len=ans.length();
for(int i=0;i<Len;i++){
if(ans[i]=='#'){
F=0;
break;
}
}
if(F)cout<<ans<<endl;
else puts("ERR");
}
}
return 0;
}
T4
二分答案,看一个点最晚需要在什么时候种树,然后贪心判断。
然后为什么我就是想不到二分答案,而是一直在想树形dp?
个人觉得是平时认为难题就是dp的思路固化了,应该做做其他的难题。
#include <bits/stdc++.h>
#define int __int128
using namespace std;
int read(){
int x=0,f=0;char c=getchar();
while(c>'9'||c<'0')f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return f?-x:x;
}
void write(int x){
if(x>9)write(x/10);
putchar(x%10+'0');
}
int n,cnt,h[100005],a[100005],b[100005],c[100005],d[100005],in[100005],maxin;
struct edge{
int v,nxt;
}e[200005];
vector<int>G[100005];
void adde(int u,int v){
e[++cnt].nxt=h[u];
h[u]=cnt;
e[cnt].v=v;
}
int tim[100005],minn[100005];
struct node{
int id;
inline bool operator<(const node &t)const{return minn[id]>minn[t.id];}
};
priority_queue<node>q;
int Sum(int id,int s,int t){
if(c[id]>=0)return b[id]*(t-s+1)+((t-s+1)*(s+t)>>1)*c[id];
else{
if(b[id]+c[id]*t>0)return b[id]*(t-s+1)+((t-s+1)*(s+t)>>1)*c[id];
else if(b[id]+c[id]*s<=0)return t-s+1;
else{
int k=(b[id]-1)/(-c[id]);
return b[id]*(k-s+1)+((k-s+1)*(k+s)>>1)*c[id]+t-k;
}
}
}
int get(int id,int t){
int l=1,r=n,mid,res=0;
while(l<=r){
mid=l+r>>1;
if(Sum(id,mid,t)>=a[id])res=mid,l=mid+1;
else r=mid-1;
}
return res;
}
void dfs1(int x){
for(int v:G[x]){
dfs1(v);
minn[x]=min(minn[x],minn[v]-1);
}
}
bool ch(int x){
while(!q.empty())q.pop();
for(int i=1;i<=n;i++){
minn[i]=tim[i]=get(i,x);
if(tim[i]<1)return 0;
}
dfs1(1);
q.push(node({1}));
int tot=0;
while(!q.empty()){
int tmp=q.top().id;
q.pop();
tot++;
if(minn[tmp]<tot)return 0;
for(int v:G[tmp])q.push(node({v}));
}
return 1;
}
void dfs(int x,int fa){
for(int i=h[x];i;i=e[i].nxt){
if(e[i].v==fa)continue;
G[x].push_back(e[i].v);
dfs(e[i].v,x);
}
}
signed main()
{
n=read();
for(int i=1;i<=n;i++){
a[i]=read(),b[i]=read(),c[i]=read();
}
for(int i=1,u,v;i<n;i++)u=read(),v=read(),adde(u,v),adde(v,u);
dfs(1,0);
int l=n,r=1e9,mid,res=r;
while(l<=r){
mid=l+r>>1;
if(ch(mid))res=mid,r=mid-1;
else l=mid+1;
}
write(res);
return 0;
}
最后,是查估分的时候我妈给我看的视频
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?