Problem A 时之终结

构造一个含有$n$个节点的无重边无自环的有向图,

使得从$1$出发,每一次经过一条$(u,v) (u < v)$的边到达节点$n$的方案恰好有$y$种。

对于$100\%$的数据,输出的无向图顶点树$n \leq 64 $给出的$y \leq 10^{18}$

Sol : 首先构造$63$个点的完全图,然后向第64个顶点连边,原问题等价于将$y$二进制拆分。

   这样构造可以获得满分:复杂度$O( {log_2}^2 n)$

  1. # include <bits/stdc++.h>
  2. # define int long long
  3. using namespace std;
  4. bool mp[][];
  5. signed main()
  6. {
  7. int y; scanf("%lld",&y);
  8. int cnt=;
  9. for (int i=;i<=;i++) for (int j=i+;j<=;j++) mp[i][j]=,cnt++;
  10. for (int i=;i<=;i++) if ((y>>i)&1ll) mp[i+][]=,cnt++;
  11. printf("64 %lld\n",cnt);
  12. for (int i=;i<=;i++)
  13. for (int j=i+;j<=;j++)
  14. if (mp[i][j]) printf("%lld %lld \n",i,j);
  15. return ;
  16. }

A.cpp

  Problem B 博士之时

$n$个节点,每个节点的度最多为$2$的图,共有$2$种不同的颜色,每一条相邻边都是不同色(0/1)的。

求出有多少种可能的重排置换,使得每个一对原本没有通过某种颜色进行连接的节点,出现在了这种颜色的连接中。

对于$100\%$的数据$n\leq 2\times 10^5$ , 图中每个点的度数最多为$2$。

Sol : 图中所有节点的度数小于等于2的可能只有是环或者链,而整个图一定是由一些单独的环和单独的链和孤立的点组成的。

     考虑链的情况,相同长度的链是可以互相交换的,同时考虑含有奇数条边的链又可以中心对称翻转的,而含偶数条边的链不行。

     考虑环的情况,相同长度的环是可以相互交换的,同时考虑每个环是可以转动这个环中的节点数次的。

     所以,我们有下列算法。

   对于链,分含奇数条边的链和偶数条边的链的讨论。

  • 奇数条边的链(设长度为$i$的奇数条边有$j$条): $2^j \times j!$
  • 偶数条边的链(设长度为$i$的奇数条边有$j$条):$ j!$

   对于环,无需分奇数偶数讨论。

设长度为$i$的环有$j$个:$j! \times i^j$

设有$k$个孤立点,显然这些孤立点可以任意排列:$k!$

将上述情况相乘就是合法的答案,如果用$n!$减去就是不合法的答案。

  复杂度是$O(n)$

  1. # include <bits/stdc++.h>
  2. # define int long long
  3. using namespace std;
  4. const int N=2e5+,mo=1e9+;
  5. struct rec{ int pre,to,w; rec() { w=-; } }a[N<<];
  6. bool vis[N];
  7. int du[N],head[N],jc[N],Pow2[N];
  8. int tot,n,m1,m2,cnt;
  9. bool flag;
  10. int col;
  11. map<int,int>circle,chain_even;
  12. map<pair<int,int>,int>chain_odd;
  13. int Pow(int x,int n)
  14. {
  15. int ans=;
  16. while (n) {
  17. if (n&) ans=ans*x%mo;
  18. x=x*x%mo;
  19. n>>=;
  20. }
  21. return ans%mo;
  22. }
  23. void adde(int u,int v,int w)
  24. {
  25. a[++tot].pre=head[u];
  26. a[tot].to=v;
  27. a[tot].w=w;
  28. head[u]=tot;
  29. }
  30. void dfs1(int u)
  31. {
  32. vis[u]=;
  33. for (int i=head[u];i;i=a[i].pre) {
  34. int v=a[i].to; if (vis[v]) continue;
  35. if (!flag) col=a[i].w,flag=;
  36. cnt++; dfs1(v);
  37. }
  38. }
  39. void dfs2(int u)
  40. {
  41. vis[u]=;
  42. for (int i=head[u];i;i=a[i].pre) {
  43. int v=a[i].to; if (vis[v]) continue;
  44. cnt++; dfs2(v);
  45. }
  46. }
  47. signed main()
  48. {
  49. int num; scanf("%lld",&num);
  50. scanf("%lld%lld%lld",&n,&m1,&m2);
  51. for (int i=;i<=m1;i++) {
  52. int u,v; scanf("%lld%lld",&u,&v);
  53. adde(u,v,); adde(v,u,);
  54. du[u]++; du[v]++;
  55. }
  56. for (int i=;i<=m2;i++) {
  57. int u,v; scanf("%lld%lld",&u,&v);
  58. adde(u,v,); adde(v,u,);
  59. du[u]++; du[v]++;
  60. }
  61.  
  62. jc[]=; for (int i=;i<=;i++) jc[i]=jc[i-]*i%mo;
  63. Pow2[]=; for (int i=;i<=;i++) Pow2[i]=Pow2[i-]*%mo;
  64.  
  65. for (int i=;i<=n;i++) if (!vis[i] && du[i]==) {
  66. cnt=; col=-; flag=false; dfs1(i);
  67. if (cnt&) chain_odd[make_pair(cnt,col)]++;
  68. else chain_even[cnt]++;
  69. }
  70. for (int i=;i<=n;i++) if (!vis[i] && du[i]==) {
  71. cnt=; dfs2(i); circle[cnt]++;
  72. }
  73. int res=;
  74. for (int i=;i<=n;i++) if (!vis[i]) res++;
  75.  
  76. int ret=jc[res]; map<int,int>::iterator it;
  77. for (it = circle.begin() ; it != circle.end() ; ++it) {
  78. int i=it->first,j=it->second;
  79. ret=ret*jc[j]%mo*Pow(i,j)%mo;
  80. }
  81. for (it = chain_even.begin(); it!=chain_even.end() ; ++it) {
  82. int i=it->first,j=it->second;
  83. ret=ret*jc[j]%mo;
  84. }
  85. map<pair<int,int>,int>::iterator it2;
  86.  
  87. for (it2 = chain_odd.begin() ; it2 != chain_odd.end() ; ++it2) {
  88. pair<int,int> p=it2->first; int i=p.first,j=it2->second;
  89. ret=ret*jc[j]%mo*Pow2[j]%mo;
  90. }
  91.  
  92. int ans = ((jc[n] - ret) % mo + mo) % mo;
  93. printf("%lld\n",ans);
  94.  
  95. return ;
  96. }

B.cpp

  Problem C 曾有两次

给出无向连通图$G$,有$n$个点和$m$条边,

对于每一个点,求删除一条边后这个点到$1$节点的距离可能的最大值

对于$100\%$的数据满足,$n\leq 2\times 10^5 , m \leq 5 \times 10^5$

Sol: 删除的边一定是最短路树上该点和其父节点的连边。

  于是直接建出最短路树,然后依次考虑每一条非树边$(u,v)$

  对于链$u -> lca(u,v) $ 不含lca的所有点都可以先最短路树的叶子节点走,经过枚举的这一条边,然后从$v$节点走到根。

  对于链$v -> lca(u,v) $ 不含lca的所有点同理。

  这样对于在链上的一个节点$k$,那么对其用$dist(k,u) + w(u,v) + dist(1,v)$更新即可。

注意到$dist(k,u)$ 这个可以表示为$dist(1,u) - dist(1,k)$ 原来的式子可以化为 $dist(1,u) - dist(1,k) + w(u,v) + dist(1,v) $

  只有$dist(1,k)$是定值,所以我们可以最后统一处理,我们只需要使用$dist(1,u)  + w(u,v) + dist(1,v) $来更新每个节点的答案即可。

  这就变成了在树上维护区间更新一个min值然后单点查询,直接使用树链剖分维护即可。

  复杂度是$O(m { log_2 }^2n )$

  1. # pragma GCC optimize()
  2. # include <bits/stdc++.h>
  3. # define int long long
  4. # define inf (1e14)
  5. using namespace std;
  6. const int N=2e5+;
  7. const int M=5e5+;
  8. struct rec{ int pre,to,w;}a[M<<];
  9. struct edge{ int u,v,w;}rec[M<<];
  10. int n,m,tot=;
  11. int head[N],d[N],e[N],f[N],dep[N],size[N];
  12. int dfn[N],top[N],g[N][];
  13. bool b[M<<];
  14. vector<int>E[N];
  15. pair<int,int>pre[N];
  16. inline int read()
  17. {
  18. int X=,w=; char c=;
  19. while(c<''||c>'') {w|=c=='-';c=getchar();}
  20. while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
  21. return w?-X:X;
  22. }
  23. void write(int x)
  24. {
  25. if (x>) write(x/);
  26. putchar(''+x%);
  27. }
  28. void adde(int u,int v,int w)
  29. {
  30. a[++tot].pre=head[u];
  31. a[tot].to=v;
  32. a[tot].w=w;
  33. head[u]=tot;
  34. }
  35. struct node {
  36. int id,len;
  37. };
  38. struct cmp {
  39. bool operator () (node x,node y) {
  40. return x.len > y.len ;
  41. }
  42. };
  43. priority_queue<node,vector<node>,cmp>q;
  44. bool vis[N];
  45. void dijkstra(int s)
  46. {
  47. memset(vis,false,sizeof(vis));
  48. memset(d,0x3f,sizeof(d));
  49. d[s]=; q.push((node){s,});
  50. while (!q.empty()) {
  51. node u=q.top();q.pop();
  52. if (vis[u.id]) continue;
  53. vis[u.id]=;
  54. for (int i=head[u.id];i;i=a[i].pre) {
  55. int v=a[i].to,w=a[i].w;
  56. if (d[v]-w>d[u.id]) {
  57. e[v]=i; pre[v]=make_pair(u.id,w); d[v]=d[u.id]+w;
  58. q.push((node){v,d[v]});
  59. }
  60. }
  61. }
  62. }
  63. void dfs1(int u,int fa)
  64. {
  65. f[u]=fa; dep[u]=dep[fa]+; size[u]=;
  66. for (int i=;i<E[u].size();i++) {
  67. int v=E[u][i]; if (v==fa) continue;
  68. dfs1(v,u); size[u]+=size[v];
  69. }
  70. }
  71. void dfs2(int u,int fa,int tp)
  72. {
  73. dfn[u]=++dfn[]; top[u]=tp;
  74. int son=-;
  75. for (int i=;i<E[u].size();i++) {
  76. int v=E[u][i]; if (v==fa) continue;
  77. if (son==-||size[v]>size[son]) son=v;
  78. }
  79. if (son!=-) dfs2(son,u,tp);
  80. for (int i=;i<E[u].size();i++) {
  81. int v=E[u][i]; if (v==fa) continue;
  82. if (v!=son) dfs2(v,u,v);
  83. }
  84. }
  85. # define ls (x<<)
  86. # define rs (x<<|)
  87. # define lson ls,l,mid
  88. # define rson rs,mid+,r
  89. # define mid (l+r>>)
  90. struct Segmengt_Tree{
  91. int tag,ret;
  92. Segmengt_Tree() { tag=-; ret=inf;}
  93. }tr[N<<];
  94. void down(int x)
  95. {
  96. if (tr[x].tag==-) return;
  97. tr[ls].ret=min(tr[ls].ret,tr[x].tag);
  98. tr[rs].ret=min(tr[rs].ret,tr[x].tag);
  99. tr[ls].tag=(tr[ls].tag==-)?tr[x].tag:min(tr[x].tag,tr[ls].tag);
  100. tr[rs].tag=(tr[rs].tag==-)?tr[x].tag:min(tr[x].tag,tr[rs].tag);
  101. tr[x].tag=-;
  102. }
  103. void update(int x,int l,int r,int opl,int opr,int d)
  104. {
  105. if (opl<=l &&r<=opr) {
  106. if (tr[x].tag==-) tr[x].tag=d;
  107. else tr[x].tag=min(tr[x].tag,d);
  108. tr[x].ret=min(tr[x].ret,d);
  109. return;
  110. }
  111. down(x);
  112. if (opl<=mid) update(lson,opl,opr,d);
  113. if (opr>mid) update(rson,opl,opr,d);
  114. tr[x].ret=min(tr[ls].ret,tr[rs].ret);
  115. }
  116. int query(int x,int l,int r,int opl,int opr)
  117. {
  118. if (opl<=l&&r<=opr) return tr[x].ret;
  119. down(x);
  120. int ret=inf;
  121. if (opl<=mid) ret=min(ret,query(lson,opl,opr));
  122. if (opr>mid) ret=min(ret,query(rson,opl,opr));
  123. return ret;
  124. }
  125. int lca(int u,int v)
  126. {
  127. if (dep[u]<dep[v]) swap(u,v);
  128. for (int i=;i>=;i--)
  129. if (dep[g[u][i]]>=dep[v]) u=g[u][i];
  130. if (u==v) return u;
  131. for (int i=;i>=;i--)
  132. if (g[u][i]!=g[v][i]) u=g[u][i],v=g[v][i];
  133. return g[u][];
  134. }
  135. void update(int u,int v,int d)
  136. {
  137. int f1=top[u],f2=top[v];
  138. while (f1!=f2) {
  139. if (dep[f1]<dep[f2]) swap(f1,f2);
  140. update(,,n,dfn[f1],dfn[u],d);
  141. u=f[f1]; f1=top[u];
  142. }
  143. if (dep[u]<dep[v]) swap(u,v);
  144. update(,,n,dfn[v]+,dfn[u],d);
  145. }
  146. int query(int x){
  147. return query(,,n,dfn[x],dfn[x]);
  148. }
  149. main()
  150. {
  151. int num=read();
  152. n=read();m=read();
  153. for (int i=;i<=m;i++) {
  154. int u=read(),v=read(),w=read();
  155. adde(u,v,w); rec[tot]=(edge){u,v,w}; adde(v,u,w);
  156. }
  157. dijkstra();
  158. for (int i=;i<=n;i++) {
  159. b[e[i]]=b[e[i]^]=;
  160. E[i].push_back(pre[i].first);
  161. E[pre[i].first].push_back(i);
  162. }
  163. dfs1(,); dfs2(,,);
  164. for (int i=;i<=n;i++) g[i][]=f[i];
  165. for (int i=;i<=;i++) for (int j=;j<=n;j++) g[j][i]=g[g[j][i-]][i-];
  166. for (int i=;i<=tot;i+=)
  167. if (!b[i]) {
  168. int u=rec[i].u,v=rec[i].v,w=rec[i].w,l=lca(u,v);
  169. update(u,l,d[v]+w+d[u]); update(v,l,d[u]+w+d[v]);
  170. }
  171. putchar(''); putchar(' ');
  172. for (int i=;i<=n;i++) {
  173. int t=query(i);
  174. if (t>=inf) putchar('-'),putchar('');
  175. else write(t-d[i]);
  176. putchar(' ');
  177. }
  178. putchar('\n');
  179. return ;
  180. }

C.cpp

HGOI20190809 省常中互测2的更多相关文章

  1. HGOI 20190816 省常中互测8

    Problem A  有两条以(0,0)为端点,分别经过(a,b),(c,d)的射线,你要求出夹在两条射线中间,且距离(0,0)最近的点(x,y) 对于$100\%$的数据满足$1 \leq T \l ...

  2. HGOI20190814 省常中互测7

    Problem A 中间值 对于$2$个非严格单增序列$\{A_n\} , \{B_n\}$,维护下列两个操作: 1 x y z: (x=0)时将$A_y = z$ , (x=1)时将$B_y = z ...

  3. HGOI20190813 省常中互测6

    Problem A 蛋糕 将$n \times m $大小的蛋糕切成每块为$1 \times 1$大小的$n\times m$块. 交换任意两块蛋糕的切割顺序的方案算作一种. 对于$100 \%$的数 ...

  4. HGOI20190811 省常中互测4

    Problem A magic 给出一个字符串$S$,和数字$n$,要求构造长度为$n$只含有小写字母的字符串$T$, 使得在$T$中存在删除且仅删除一个子串使得$S=T$成立. 输出$T$的构造方案 ...

  5. HGOI20190810 省常中互测3

    Problem A  夏洛特 若当前处在点$(x,y)$下一时刻可以向该点四周任意方向走动一步, 初始在$(0,0)$是否存在一条合法的路线满足下列$n$个限制: 每一个限制形如$t_i , x_i ...

  6. HGOI20190808 省常中互测1

    Problem A  sum 给出$n$个元素的序列$\{a_i\}$,求出两个不相交连续子序列的最大元素和. 即对于$1 \leq A \leq B \leq C \leq D \leq n$最大化 ...

  7. HGOI20190812 省常中互测5

    Task 1 辩论 有N 个参加辩论的候选人,每个人对这两个议题都有明确的态度,支持或反对.作为组织者,小D 认真研究了每个候选人,并给每个人评估了一个非负的活跃度,他想让活跃度之和尽可能大.选出的候 ...

  8. 【2018集训队互测】【XSY3372】取石子

    题目来源:2018集训队互测 Round17 T2 题意: 题解: 显然我是不可能想出来的……但是觉得这题题解太神了就来搬(chao)一下……Orzpyz! 显然不会无解…… 为了方便计算石子个数,在 ...

  9. 【CH 弱省互测 Round #1 】OVOO(可持久化可并堆)

    Description 给定一颗 \(n\) 个点的树,带边权. 你可以选出一个包含 \(1\) 顶点的连通块,连通块的权值为连接块内这些点的边权和. 求一种选法,使得这个选法的权值是所有选法中第 \ ...

随机推荐

  1. 解决ubuntu命令行中文乱码

    解决方法: 1.安装zhcon 登入用户后,输入 1 sudo apt-get install zhcon 2.启动zhcon 输入 1 zhcon --utf8  PS:zhcon支持中文输入法,按 ...

  2. CentOS7安装SVN1.9.12

    检查卸载原有的svn svn --version # 检查是否原有svn yum remove svn # 卸载原有svn 安装依赖: apr-1.6.5 mkdir /opt/software/sv ...

  3. python __dict__ 跟 dir()的区别

    __dict__:要是对象的话返回的是一个对象自身的实例属性.不包括类的属性:要是类的__dict__则不包括父类的属性,只包含自身类属性[方法.类变量],不包括实例属性.正是这样.每个实例的实例属性 ...

  4. Python模拟进度条

    import time for i in range(0,101,2) time.sleep(0.2) num = i // 2 per = '\r %s %% : %s'%(i,'*'*num) p ...

  5. copy小练习

    # 1. # 有如下 # v1 = {'郭宝元', '李杰', '太白', '梦鸽'} # v2 = {'李杰', '景女神} # 请得到 v1 和 v2 的交集并输出 # 请得到 v1 和 v2 的 ...

  6. Java中「与运算,或运算,异或运算,取反运算。」

    版权声明一:本文为博主原创文章,转载请附上原文出处链接和本声明.版权声明二:本网站的所有作品会及时更新,欢迎大家阅读后发表评论,以利作品的完善.版权声明三:对不遵守本声明或其他违法.恶意使用本网内容者 ...

  7. 漏洞:阿里云盾phpMyAdmin <=4.8.1 后台checkPageValidity函数缺陷可导致GETSHELL

    阿里云盾提示phpMyAdmin <=4.8.1会出现漏洞有被SHELL风险,具体漏洞提醒: 标题 phpMyAdmin <=4.8.1 后台checkPageValidity函数缺陷可导 ...

  8. C++参数传递与STL

    C++参数传递与STL 这是一篇备忘录形式的内容,涉及到的内容比较基础 今天写了一个小算法,用一个set在函数间传递,记录各个函数中的结果.但是最后结果显示set中的元素是0个.查了一下才发现,用来C ...

  9. Ubuntu Linux 查看、编辑、比较二进制文件

    查看二进制有以下几种方法: 方法一:hexdump apt-get install libdata-hexdumper-perl 安装好之后就可以直接hexdump your_binary_file ...

  10. Mac下安装svn服务器

    本文转载自http://www.cnblogs.com/czq1989/p/4913692.html Mac默认已经安装了svn,我们只需要进行配置并开启就可以了 首先我们可以验证一下是否安装了svn ...