T1 宝藏

解题思路

考场上一眼出 \(nlog^2\) 做法,然后没看见是 1s 3e5 的数据,我竟然以为自己切了??

考完之后尝试着把二分改为指针的移动,然后就过了??或许是数据水吧,感觉自己的做法指针好像并不满足单调性。。

口胡一下正解,做法差不多,只不过枚举的方式改变了,但是都需要先对于 w 进行排序,枚举每一种长度的序列,单调指针维护最大的合法的值。

这个是有单调性的,然后主席树或者权值线段树维护均可。

code

其实是假做法

  1. #include<bits/stdc++.h>
  2. #define int long long
  3. #define ull unsigned long long
  4. #define f() cout<<"RP++"<<endl
  5. #define ls x<<1
  6. #define rs x<<1|1
  7. using namespace std;
  8. inline int read()
  9. {
  10. int x=0,f=1;char ch=getchar();
  11. while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
  12. while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
  13. return x*f;
  14. }
  15. const int N=3e5+10,M=1e6+10;
  16. int n,m,q,lim,ans[N];
  17. struct Node{int w,t;}s[N];
  18. struct Segment_Tree
  19. {
  20. int root,all;
  21. struct node{int siz,dat;}tre[M<<2];
  22. #define push_up(x) tre[x].dat=tre[ls].dat+tre[rs].dat,tre[x].siz=tre[ls].siz+tre[rs].siz
  23. void insert(int x,int l,int r,int pos,int val)
  24. {
  25. if(l==r) return tre[x].siz+=val,tre[x].dat+=val*pos,void();
  26. int mid=(l+r)>>1;
  27. if(pos<=mid) insert(ls,l,mid,pos,val);
  28. else insert(rs,mid+1,r,pos,val);
  29. push_up(x);
  30. }
  31. int query(int x,int l,int r,int k)
  32. {
  33. if(!tre[x].siz||!k) return 0;
  34. if(l==r) return tre[x].dat*k/tre[x].siz;
  35. int mid=(l+r)>>1;
  36. if(tre[ls].siz>k) return query(ls,l,mid,k);
  37. return tre[ls].dat+query(rs,mid+1,r,k-tre[ls].siz);
  38. }
  39. }T1,T2;
  40. bool comp(Node x,Node y){return x.w<y.w;};
  41. #undef int
  42. int main()
  43. {
  44. #define int long long
  45. freopen("treasure.in","r",stdin); freopen("treasure.out","w",stdout);
  46. n=read(); m=read(); q=read(); memset(ans,-1,sizeof(ans));
  47. for(int i=1;i<=n;i++) s[i].w=read(),s[i].t=read(),lim=max(lim,s[i].t);
  48. sort(s+1,s+n+1,comp); for(int i=1;i<=n;i++) T2.insert(1,0,lim,s[i].t,1);
  49. for(int i=1,val=0;i<=n;i++)
  50. {
  51. T2.insert(1,0,lim,s[i].t,-1); val=min(val,min(i-1,n-i));
  52. while(val<min(i-1,n-i)&&T1.query(1,1,lim,val+1)+T2.query(1,1,lim,val+1)+s[i].t<=m) val++;
  53. while(val>0&&T1.query(1,1,lim,val)+T2.query(1,1,lim,val)+s[i].t>m) val--;
  54. ans[val]=max(ans[val],s[i].w); T1.insert(1,0,lim,s[i].t,1);
  55. }
  56. for(int i=n/2;i>=0;i--) ans[i]=max(ans[i],ans[i+1]);
  57. while(q--){int x;x=read();printf("%lld\n",ans[min(n,x/2)]);}
  58. return 0;
  59. }

T2 寻找道路

解题思路

首先考虑去除前导 0 的影响,直接搜索一遍查找所有到 1 节点距离为 0 的点记录下来就好了。

剩下的部分就是字典序以及长度的问题了,那么长度的问题直接 BFS 就可以了。

字典序大小的话,对于队列中长度一致并且数字序列相同的一起拿出来,然后优先扫 0 边权的边再扫 1 边权的边。

标记一下,保证每个节点只访问一次。

code

  1. #include<bits/stdc++.h>
  2. #define int long long
  3. #define ull unsigned long long
  4. #define f() cout<<"RP++"<<endl
  5. using namespace std;
  6. inline int read()
  7. {
  8. int x=0,f=1;char ch=getchar();
  9. while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
  10. while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
  11. return x*f;
  12. }
  13. const int N=1e6+10,mod=1e9+7,INF=1e18;
  14. int n,m,top,sta[N],len[N],dis[N];
  15. int tot=1,head[N],ver[N<<1],nxt[N<<1],edge[N<<1];
  16. vector<int> dis0;
  17. queue<int> q;
  18. bool vis[N];
  19. void add_edge(int x,int y,int val)
  20. {
  21. ver[++tot]=y; edge[tot]=val;
  22. nxt[tot]=head[x]; head[x]=tot;
  23. }
  24. #undef int
  25. int main()
  26. {
  27. #define int long long
  28. freopen("path.in","r",stdin); freopen("path.out","w",stdout);
  29. n=read(); m=read(); memset(len,0x3f,sizeof(len)); dis[1]=len[1]=0;
  30. for(int i=1,x,y,z;i<=m;i++) x=read(),y=read(),z=read(),add_edge(x,y,z);
  31. q.push(1); dis0.push_back(1);
  32. while(!q.empty())
  33. {
  34. int x=q.front(); q.pop();
  35. for(int i=head[x];i;i=nxt[i])
  36. if(!vis[ver[i]]&&!edge[i])
  37. vis[ver[i]]=true,dis0.push_back(ver[i]),q.push(ver[i]);
  38. }
  39. for(auto it:dis0) q.push(it),dis[it]=len[it]=0;
  40. while(!q.empty())
  41. {
  42. top=0; sta[++top]=q.front(); q.pop();
  43. while(!q.empty()&&len[q.front()]==len[sta[1]]&&dis[q.front()]==dis[sta[1]])
  44. sta[++top]=q.front(),q.pop();
  45. for(int i=1;i<=top;i++)
  46. {
  47. int x=sta[i];
  48. for(int j=head[x];j;j=nxt[j])
  49. {
  50. int to=ver[j],val=edge[j];
  51. if(val||vis[to]||len[to]<=len[x]+1) continue;
  52. len[to]=len[x]+1; dis[to]=dis[x]*2%mod;
  53. vis[to]=true; q.push(to);
  54. }
  55. }
  56. for(int i=1;i<=top;i++)
  57. {
  58. int x=sta[i];
  59. for(int j=head[x];j;j=nxt[j])
  60. {
  61. int to=ver[j],val=edge[j];
  62. if(!val||vis[to]||len[to]<=len[x]+1) continue;
  63. len[to]=len[x]+1; dis[to]=(dis[x]*2+1)%mod;
  64. vis[to]=true; q.push(to);
  65. }
  66. }
  67. }
  68. for(int i=2;i<=n;i++) printf("%lld ",len[i]>=INF?-1ll:dis[i]);
  69. return 0;
  70. }

T3 猪国杀

解题思路

其实是个假期望,计数 DP 。

我们只需要知道每一种方案的总和了,最后乘上一个 \(A^n\) 。

设 \(g_{i,j,k}\) 表示有 多少个⻓度为 \(i\) 的正整数序列满足每一个数字不大于 \(j\) 且所有数字总和不超过 \(k\) 。

假设我们能够求出来这个值,考虑如何计算答案。

枚举选的牌中的最大值 \(j\) ,最大值个数 \(k\) ,以及选了 \(i\) 个小于 \(j\) 的牌,于是就有了:

\[\sum\limits_{i=0}^n\sum\limits_{j=1}^A\sum\limits_{k=1}^{n-i}g_{i,j-1,m-j\times k}\times \binom{n}{i}\sum\limits_{t=k}^{n-i}\binom{n-i}{t}\times(A-j)^{n-i-t}
\]

对于计算过方案数的两个序列就可以视为序列中的元素是等价的了,也就是再乘上一个可重集排列。

因为我们要选择 \(k\) 个 \(j\) 但是序列中不一定只有 \(k\) 个 \(j\) 因此我们需要让前面的牌的总和是 \(m-j\times k\) 然后枚举后面有多少个 \(j\) 同时计算剩下的取值的个数。

对于 \(g_{i,j,k}\) 可以通过枚举多少个大于 \(j\) 的数字进行计算,可以运用挡板法,由于挡板之间 1 的个数可能会超过 \(j\) 因此需要容斥一下:

\[g_{i,j,k}=\sum\limits_{t=0}^i(-1)^t\binom{i}{t}\binom{k-t\times j}{i}
\]

code

  1. #include<bits/stdc++.h>
  2. #define int long long
  3. #define ull unsigned long long
  4. #define f() cout<<"RP++"<<endl
  5. using namespace std;
  6. inline int read()
  7. {
  8. int x=0,f=1;char ch=getchar();
  9. while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
  10. while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
  11. return x*f;
  12. }
  13. const int N=110,M=1010,mod=998244353;
  14. int n,m,lim,mx,ans,fac[M],ifac[M];
  15. void add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
  16. int power(int x,int y,int p=mod)
  17. {
  18. int temp=1;
  19. while(y)
  20. {
  21. if(y&1) temp=temp*x%p;
  22. x=x*x%p; y>>=1;
  23. }
  24. return temp;
  25. }
  26. int C(int x,int y){return x<y?0:fac[x]*ifac[y]%mod*ifac[x-y]%mod;}
  27. int g(int i,int j,int k)
  28. {
  29. int sum=0;
  30. for(int p=0,sym=1;p<=i;p++,sym=-sym)
  31. {
  32. int temp=C(i,p)*C(k-p*j,i)%mod;
  33. if(temp) add(sum,sym*temp+((~sym)?0:mod));
  34. else break;
  35. }
  36. return sum;
  37. }
  38. #undef int
  39. int main()
  40. {
  41. #define int long long
  42. freopen("legend.in","r",stdin); freopen("legend.out","w",stdout);
  43. n=read(); m=read(); lim=read(); mx=max(n,max(m,lim));
  44. fac[0]=ifac[0]=1; for(int i=1;i<=mx;i++) fac[i]=fac[i-1]*i%mod;
  45. ifac[mx]=power(fac[mx],mod-2); for(int i=mx-1;i>=1;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
  46. for(int i=0;i<=n;i++)
  47. for(int j=1;j<=lim;j++)
  48. for(int k=1;k<=n-i;k++)
  49. {
  50. int base=0,temp=C(n,i)%mod*g(i,j-1,m-j*k)%mod;
  51. if(!temp) continue;
  52. for(int p=k;p<=n-i;p++)
  53. {
  54. int temp=C(n-i,p); if(!temp) break;
  55. add(base,temp*power(lim-j,n-i-p)%mod);
  56. }
  57. if(base) add(ans,base*temp%mod);
  58. }
  59. printf("%lld",ans*power(power(lim,n),mod-2)%mod); return 0;
  60. }

T4 数树

解题思路

枚举以哪个节点为根以及子树和 T2 的匹配程度来判断。

具体实现可以 Hash+素数 防止重复。

code

  1. #include<bits/stdc++.h>
  2. #define int long long
  3. #define ull unsigned long long
  4. #define f() cout<<"RP++"<<endl
  5. using namespace std;
  6. inline int read()
  7. {
  8. int x=0,f=1;char ch=getchar();
  9. while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
  10. while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
  11. return x*f;
  12. }
  13. const int N=3e3+10,M=20,bas=23,mod=998244353;
  14. int n,m,cnt,ans,pri[N],siz[N];
  15. int tot=1,head[N],ver[N<<1],nxt[N<<1];
  16. ull has[N];
  17. unordered_map<ull,int> ys,f[N];
  18. unordered_map<ull,bool> can,mp;
  19. vector<int> v[M];
  20. bitset<N> vis;
  21. void add_edge(int x,int y)
  22. {
  23. ver[++tot]=y;
  24. nxt[tot]=head[x];
  25. head[x]=tot;
  26. }
  27. void Get_Prime()
  28. {
  29. for(int i=2;i<=1000;i++)
  30. {
  31. if(!vis[i]) pri[++cnt]=i;
  32. for(int j=1;j<=cnt&&pri[j]*i<=1000;j++)
  33. {
  34. vis[i*pri[j]]=true;
  35. if(i%pri[j]==0) break;
  36. }
  37. }
  38. }
  39. void pre_dfs(int x,int fa)
  40. {
  41. siz[x]=has[x]=1;
  42. for(auto to:v[x])
  43. {
  44. if(to==fa) continue;
  45. pre_dfs(to,x); siz[x]+=siz[to];
  46. has[x]+=has[to]*pri[siz[to]+bas];
  47. }
  48. mp.insert(make_pair(has[x],true));
  49. ys.insert(make_pair(has[x],siz[x]+bas));
  50. }
  51. void dfs(int x,int fa)
  52. {
  53. f[x].insert(make_pair(1,1));
  54. for(int i=head[x];i;i=nxt[i])
  55. {
  56. int to=ver[i]; if(to==fa) continue;
  57. unordered_map<ull,int> temp=f[x]; dfs(to,x);
  58. for(auto it1:temp) for(auto it2:f[to])
  59. {
  60. ull rec=it1.first+it2.first*pri[ys.find(it2.first)->second];
  61. f[x][rec]=(f[x][rec]+it1.second*it2.second)%mod;
  62. }
  63. }
  64. vector<ull> dela;
  65. for(auto it:f[x]) if(mp.find(it.first)==mp.end()) dela.push_back(it.first);
  66. for(auto it:dela) f[x].erase(it);
  67. }
  68. #undef int
  69. int main()
  70. {
  71. #define int long long
  72. freopen("count.in","r",stdin); freopen("count.out","w",stdout);
  73. n=read(); Get_Prime();
  74. for(int i=1,x,y;i<n;i++)
  75. x=read(),y=read(),
  76. add_edge(x,y),add_edge(y,x);
  77. m=read();
  78. for(int i=1,x,y;i<m;i++)
  79. x=read(),y=read(),
  80. v[x].push_back(y),v[y].push_back(x);
  81. for(int i=1;i<=m;i++) pre_dfs(i,0),can.insert(make_pair(has[i],true));
  82. dfs(1,0);
  83. for(auto it:can)
  84. for(int i=1;i<=n;i++)
  85. if(f[i].find(it.first)!=f[i].end())
  86. ans=(ans+f[i].find(it.first)->second)%mod;
  87. printf("%lld",ans);
  88. return 0;
  89. }

NOIP模拟84(多校17)的更多相关文章

  1. NOIP模拟83(多校16)

    前言 CSP之后第一次模拟赛,感觉考的一般. 不得不吐槽多校联测 OJ 上的评测机是真的慢... T1 树上的数 解题思路 感觉自己思维有些固化了,一看题目就感觉是线段树. 考完之后才想起来这玩意直接 ...

  2. Noip模拟79 2021.10.17(题目名字一样)

    T1 F 缩点缩成个$DAG$,然后根据每个点的度数计算期望值 1 #include<cstdio> 2 #include<cstring> 3 #include<vec ...

  3. Noip模拟18 2021.7.17 (文化课专场)

    T1 导弹袭击(数学) 显然,我们要找到最优的A,B使得一组a,b优于其他组那么可以列出: $\frac{A}{a_i}+\frac{B}{b_i}<\frac{A}{a_j}+\frac{B} ...

  4. Noip模拟55 2021.9.17(打表大胜利)

    T1 skip 普通$dp$很好打: $f[i]=max(f[j]-\sum_{k=1}^{K}k+a_i)$ 就是要注意边界问题很烦人. 1 #include<bits/stdc++.h> ...

  5. Noip模拟42 2021.8.17

    T1 卷 一看跟没有上司的舞会一样,直接敲了然后试个自己造的样例对了就跑了... 然而把它想简单了,乘积取模,还能比大小吗????? 显然不能 所以直接让对数的加和跟着$dp$直接一起跑,比大小的都用 ...

  6. Noip模拟8 2021.6.17

    T1 星际旅行 仔细一看,发现像一个欧拉路(简称一笔画). 满足"可以一笔画"的条件是: 1.所有点都有偶数条连边; 2.有偶数个点连奇数条边; 满足以上两个条件的任意一个即可一笔 ...

  7. NOIP模拟92(多校25)

    前言 所以说这次是 HZOI 多校联测巅峰????(题目,数据过水??) T1 石子合并 解题思路 签到题. 发现我们可以给每个数字附一个正负号,每个数字的贡献就是它本身乘上这个符号. 发现至少应该有 ...

  8. Noip模拟84 2021.10.27

    以后估计都是用\(markdown\)来写了,可能风格会有变化 T1 宝藏 这两天老是会的题打不对,还是要细心... 考场上打的是维护\(set\)的做法,但是是最后才想出来的,没有维护对于是没有交. ...

  9. NOIP模拟85(多校18)

    前言 好像每个题目背景所描述的人都是某部番里的角色,热切好像都挺惨的(情感上的惨). 然后我只知道 T1 的莓,确实挺惨... T1 莓良心 解题思路 首先答案只与 \(w\) 的和有关系,于是问题就 ...

随机推荐

  1. Docker入门之container篇

    启动 启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容 器重新启动. 因为 Docker 的容器实在太轻量级了,很多时候用户都是随时删除和新创建容器. ...

  2. 文件流转换(一般用于axios设置接收文件流设置时responseType: 'blob')

    文件流转换 一般用于axios设置接收文件流设置时responseType: 'blob'当接口报错时,前端因已设置responseType: 'blob'无法再接收json格式数据,会把json格式 ...

  3. SpringBoot自定义初始化Bean+HashMap优化策略模式实践

    策略模式:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 传统的策略模式一般是创建公共接口.定义公共方法-->然后创建实体类实现公共接口.根据各自的 ...

  4. go命令帮助

    Go is a tool for managing Go source code. go-->管理go源码的工具-->管理工具,包含很多功能命令 Usage: go <command ...

  5. 【转载】linux 工作队列上睡眠的认识--不要在默认共享队列上睡眠

    最近项目组做xen底层,我已经被完爆无数遍了,关键在于对内核.驱动这块不熟悉,导致分析xen代码非常吃力.于是准备细细的将 几本 linux 书籍慢慢啃啃. 正好看到LINUX内核设计与实现,对于内核 ...

  6. python matplotlib.pyplot 条形图详解

    python matplotlib.pyplot 条形图详解 一.创建直方图 可以用bar函数来创建直方图 然后用show函数显示直方图 比如: import matplotlib.pyplot as ...

  7. 设置自启动nginx(适用于其他软件)(LinuxDeploy里的Ubuntu)

    LinuxDeploy里的Ubuntu自启动nginx(适用于其他软件) 网上的教程是这样的,基本能用 1.编写脚本(这个文件及其内容安装Nginx后自动生成,没有的话内容自己Google) $ su ...

  8. ARP-NAT(MAC Address Translation)的原理

    本文部分图片来自: http://wiki.deliberant.com/faq/wireless-bridge-routing-arpnat/ https://wiki.openwrt.org/do ...

  9. 哪5种IO模型?什么是select/poll/epoll?同步异步阻塞非阻塞有啥区别?全在这讲明白了!

    系统中有哪5种IO模型?什么是 select/poll/epoll?同步异步阻塞非阻塞有啥区别? 本文地址http://yangjianyong.cn/?p=84转载无需经过作者本人授权 先解开第一个 ...

  10. Shell系列(38)- 数组操作→取值、遍历、替换、删除

    引言 在Linux平台上工作,我们经常需要使用shell来编写一些有用.有意义的脚本程序.有时,会经常使用shell数组.那么,shell中的数组是怎么表现的呢,又是怎么定义的呢?接下来逐一的进行讲解 ...