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 n3 打了,期望50分,开始搞T3.

?~80min,T3打完了,一遍过所有样例,感觉样例很水,不太放心,但没办法。

80~[120,140]min,看看T4,随便打了一点部分分,估计得分45,感觉295的成绩差不多了。

[120,140]min,然后发现T2 n3 只有35,有点崩。

?~210min,决定搞T2。

我们发现如果一个区间可消除,那么一定可以描述为从头到尾一次入栈,与栈顶相同就弹栈,最后栈为空,打出 n2 50分。

进行优化,发现可以考虑 s1,,i 的后缀。

搞了一个字典树,调了半天,比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

我们发现,对于现在的栈,如果要加入 si,那么所有最后一个字符是 si 的串会去掉最后一位,其他的会在最后补上一个 si

树就会变成这样。由于不可能出现连续的相同字母,所以我们只需要把 si 这个节点取下来,再把剩下的树挂到他的 si 边上。

字典树轻松实现。

  #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;
  }

最后,是查估分的时候我妈给我看的视频

posted @   Grisses  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
Document
点击右上角即可分享
微信分享提示