【UOJ Easy Round #1】

数论/Trie/并查集


猜数

  这题我是这样分析的……

  $a*b=g*l=n=k^2 \ and \ (g|a,g|b) \Rightarrow (g*a^‘)*(g*b^‘)=g*l=k^2 \Rightarrow a^‘ * b^‘ =\frac{l}{g}={\frac{k}{g}}^2 \Rightarrow min(a^‘+b^‘)=2* \sqrt{\frac{l}{g}} \ \ max(a^‘+b^‘)=1+\frac{l}{g}$

  然而算ans的时候还需要再乘g……我给忘了

 1 //UOJ Easy Round1 A
 2 #include<vector>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<iostream>
 8 #include<algorithm>
 9 #define rep(i,n) for(int i=0;i<n;++i)
10 #define F(i,j,n) for(int i=j;i<=n;++i)
11 #define D(i,j,n) for(int i=j;i>=n;--i)
12 using namespace std;
13 typedef long long LL;
14 const int N=1e5+10;
15 /*******************template********************/
16
17 LL n,g,l;
18 int main(){
19 #ifndef ONLINE_JUDGE
20     freopen("A.in","r",stdin);
21     freopen("A.out","w",stdout);
22 #endif
23     int T; scanf("%d",&T);
24     while(T--){
25         scanf("%lld%lld",&g,&l);
26         printf("%lld %lld\n",2*(LL)sqrt(l/g)*g,l+g);
27     }
28     return 0;
29 }

跳蚤OS

  Trie树+go指针

  所以我们其实只要实现一个沿着Trie树和go指针走的Find函数就可以(找到该字符串在Trie中的实际位置)

  这里需要特判一下根目录,因为只有它一个是以‘\‘结尾的。

  这个……yy出来以后实现还是比较容易的。

  坑爹的是strlen函数是O(n)的,所以最好拿一个变量来保存这个值。(优化了一下,用时居然rank1了,真是令人感动)

 1 //UOJ Easy Round1 B
 2 #include<vector>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<iostream>
 7 #include<algorithm>
 8 #define rep(i,n) for(int i=0;i<n;++i)
 9 #define F(i,j,n) for(int i=j;i<=n;++i)
10 #define D(i,j,n) for(int i=j;i>=n;--i)
11 using namespace std;
12 typedef long long LL;
13 inline int getint(){
14     int r=1,v=0; char ch=getchar();
15     for(;!isdigit(ch);ch=getchar()) if (ch==‘-‘) r=-1;
16     for(; isdigit(ch);ch=getchar()) v=v*10-‘0‘+ch;
17     return r*v;
18 }
19 const int N=1e6+10;
20 /*******************template********************/
21
22 int c[N][27],go[N],fa[N],n,m,tot=1;
23 char s1[N],s2[N],t[N];
24 inline int id(char ch){
25     if (ch==‘/‘) return 26;
26     else return ch-‘a‘;
27 }
28 int Find(char *s){
29     int x=1,y;
30     int l=strlen(s);
31     rep(i,l){
32         y=id(s[i]);
33         if (!c[x][y]){
34             c[x][y]=++tot;
35             fa[tot]=x;
36             t[tot]=s[i];
37         }
38         x=c[x][y];
39         if ((s[i+1]==‘/‘||i+1==l) && go[x]) x=go[x];
40     }
41     return x;
42 }
43 int main(){
44 #ifndef ONLINE_JUDGE
45     freopen("B.in","r",stdin);
46     freopen("B.out","w",stdout);
47 #endif
48     scanf("%d%d",&n,&m);
49     F(i,1,n){
50         scanf("%s%s",s1,s2);
51         int t1=Find(s1),t2=Find(s2);
52         if (t2==2) t2=1;
53         go[t1]=t2;
54     }
55     F(i,1,m){
56         scanf("%s",s1);
57         int num=0;
58         for(int t1=Find(s1);t1!=1;t1=fa[t1])
59             s2[num++]=t[t1];
60         if (num==0) s2[num++]=‘/‘;
61         D(i,num-1,0) printf("%c",s2[i]); puts("");
62     }
63     return 0;
64 }

DZY Loves Graph

  离线模拟+并查集按秩合并

  Orz pyz5715

  虽然题解看懂了,但是并不会写……

  这里是用一个数组记录下来我们每插入一条边,当前的边权和,连通块个数(如果为1则成了一棵树,可以出解了),以及修改了谁的father。

  merge操作就是修改这三个东西……

  考虑Remove,也就是删掉一条边:

  如果最后一次加边并没有修改father,那么直接删就好了……cur--

  否则:我们要将这条边断掉,此时由于我们保存了该时刻的边权和以及连通块个数,所以这些都不用考虑修改……唯一需要重新维护的是每个并查集的rank,这里我一开始yy的修改方式是:将从x到其所在并查集的root的rank都减去rank[x]。然而这样TLE了……FST了最后一个点(非常鬼畜,加一条边,减一条边,加两条边,减两条边……)一开始我以为是需要卡常数,照着神犇的代码一点一点改……然而其实是这里出了问题:每次要将这一条链上的每个点 i 的rank[fa[i]]-=rank[i]。(目前百思不得其解,留一个坑吧)

这里我们离线做,做完一个操作后先读一下,看下下一个操作是不是Remove,如果是就直接执行。(这里我的感觉是为了方便知道要撤销的操作是什么)

 1 //UOJ Easy Round1 C
 2 //orz pyz5715
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<iostream>
 7 #include<algorithm>
 8 #define rep(i,n) for(int i=0;i<n;++i)
 9 #define F(i,j,n) for(int i=j;i<=n;++i)
10 #define D(i,j,n) for(int i=j;i>=n;--i)
11 #define pb push_back
12 using namespace std;
13 typedef long long LL;
14 inline int getint(){
15     int r=1,v=0; char ch=getchar();
16     for(;ch<‘0‘ || ch>‘9‘;ch=getchar()) if (ch==‘-‘) r=-1;
17     for(;ch>=‘0‘ && ch<=‘9‘;ch=getchar()) v=(v<<3)+(v<<1)-‘0‘+ch;
18     return r*v;
19 }
20 const int N=500010;
21 /*******************template********************/
22
23 int n,m,cur,p[N],fa[N],rank[N],size[N],x,y;
24 LL w[N];
25 char cmd;
26
27 inline int getfa(int x){return fa[x]==x?x:getfa(fa[x]);}
28
29 inline void Merge(int x,int y,int val){
30     x=getfa(x), y=getfa(y);
31     w[++cur]=w[cur-1]; p[cur]=0;
32     size[cur]=size[cur-1];
33     if (x==y) return;
34     if (rank[x]<rank[y]) x^=y^=x^=y;
35     fa[p[cur]=y]=x; rank[x]+=rank[y];
36     w[cur]+=val; --size[cur];
37 }
38
39 inline void Remove(){
40     int x=p[cur--];
41     if (x){
42         for(int i=x;i!=fa[i];i=fa[i])
43             rank[fa[i]]-=rank[i];
44         fa[x]=x;
45     }
46 }
47 inline char getc(){
48     char ch;
49     while(ch=getchar(),ch<65 || ch>90);
50     return ch;
51 }
52 int main(){
53 #ifndef ONLINE_JUDGE
54     freopen("C.in","r",stdin);
55     freopen("C.out","w",stdout);
56 #endif
57     n=getint(); m=getint();
58     F(i,1,n) fa[i]=i,rank[i]=1;
59     size[0]=n;
60     cmd=getc();
61     F(i,1,m){
62         if (cmd==‘A‘){
63             x=getint(),y=getint();
64             Merge(x,y,i);
65             printf("%lld\n",size[cur]==1?w[cur]:0);
66             if (i!=m && (cmd=getc())==‘R‘) Remove();
67         }else if (cmd==‘D‘){
68             x=getint();
69             printf("%lld\n",size[cur-x]==1?w[cur-x]:0);
70             if (i!=m && (cmd=getc())!=‘R‘) while(x--) Remove();
71         }else{
72             printf("%lld\n",size[cur]==1?w[cur]:0);
73             if (i!=m) cmd=getc();
74         }
75     }
76     return 0;
77 }

时间: 2024-07-31 12:42:18

【UOJ Easy Round #1】的相关文章

UOJ Easy Round #8 T1 打雪仗 题解

题目链接: [UER #8]打雪仗 第一次做通信题,写篇\(blog\)加深印象. 首先分析题目,根据数据,最坏情况下\(m\approx \frac23n\) 刚开始时想着把进制压到更高进制输出,不过实现不来放弃了. 那么把\(2n\)分成一些长度为\(3\)的区间,对于\(1,2\)个字符,直接由小\(B\)告诉小\(A\)是否需要,如果需要则小\(A\)发送字符. 对于第\(3\)个字符,无论需不需要都由小\(A\)发出. 那么显然小\(B\)的输出长度正好为\(\frac23n\). 对

【Educationcal Codeforces Round 21】

这场edu我原本以为能清真一点-- 后来发现不仅是七题 还有各种奇奇怪怪的骚操作-- A. 随便枚举 #include<bits/stdc++.h> using namespace std; int n; int main(){ scanf("%d",&n);int x=1; for(;n/(x*10);x*=10); printf("%d\n",n/x*x+x-n); } B. xjb按照定义分一下就行了 #include<bits/st

【Educational Codeforces Round 22】

又打了一场EDU,感觉这场比23难多了啊-- 艹还是我太弱了. A. 随便贪心一下. #include<bits/stdc++.h> using namespace std; int n,sum=0,ans=-1,m; inline int read(){ int f=1,x=0;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9'); do{x=x*10+ch-'0';ch=getchar();}while(

【Educational Codeforces Round 38】D. Buy a Ticket 堆优化Dijkstra

题意 给定一张无向图,对每个点$i\in S$求$\min_{j\in S} {2\times d(i,j)+a_j}$ 考虑多源多汇最短路会超时,换个角度考虑每个$j$,如果$j=i$,那么答案为$a_i$,如果有更优的方案,那么为$i$到$j$的一条路径加上$a_j$,将这个过程看成两条路径,并且将$a_j$独立为一条路径,就得到最短路算法中的松弛操作,可以建立一个超级源点,连向各点,边权为$a_i$,那么从源点跑一遍最短路之后就是每个点所求答案 时间复杂度$O(n\log n)$ 代码 #

【Educational Codeforces Round 37】F. SUM and REPLACE 线段树+线性筛

题意 给定序列$a_n$,每次将$[L,R]$区间内的数$a_i$替换为$d(a_i)$,或者询问区间和 这题和区间开方有相同的操作 对于$a_i \in (1,10^6)$,$10$次$d(a_i)$以内肯定可以最终化为$1$或者$2$,所以线段树记录区间最大值和区间和,$Max\le2$就返回,单点暴力更新,最后线性筛预处理出$d$ 时间复杂度$O(m\log n)$ 代码 #include <bits/stdc++.h> using namespace std; typedef long

【UOJ】【UR #2】猪猪侠再战括号序列(splay/贪心)

http://uoj.ac/problem/31 纪念伟大的没有调出来的splay... 竟然那个find那里写错了!!!!!!!!!!!!! 以后要记住:一定要好好想过! (正解的话我就不写了,太简单了.. #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #

[官方软件] Easy Sysprep v4.3.29.602 【系统封装部署利器】(2016.01.22)--skyfree大神

[官方软件] Easy Sysprep v4.3.29.602 [系统封装部署利器](2016.01.22) Skyfree 发表于 2016-1-22 13:55:55 https://www.itsk.com/forum.php?mod=viewthread&tid=362766&highlight=Easy%2BSysprep [官方软件] Easy Sysprep v4.3.29.602 [系统封装部署利器](2016.01.22) [Easy Sysprep]概述:Easy Sy

Codeforces Round #254 (Div. 2) DZY Loves Chemistry【并查集基础】

一开始不知道题意是啥意思,迟放进去反应和后放进去反应有什么区别 对于第三组数据不是很懂,为啥312,132的组合是不行的 后来发现这是一道考察并查集的题目 QAQ 怒贴代码: 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <iostream> 6 #include <algorithm> 7

【UOJ#67】新年的毒瘤(Tarjan)

[UOJ#67]新年的毒瘤(Tarjan) 题面 UOJ 题解 一棵\(n\)个节点的树显然有\(n-1\)条边,在本题中意味着删去一个点之后还剩下\(n-2\)条边.那么找到所有度数为\(m-(n-2)\)的点就好了.但是因为是一棵树,所以联通,所以割点不是答案. #include<iostream> #include<cstdio> using namespace std; #define ll long long #define MAX 100100 inline int r