【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
离线模拟+并查集 按秩合并 按size合并
Orz pyz5715
虽然题解看懂了,但是并不会写……
这里是用一个数组记录下来我们每插入一条边,当前的边权和,连通块个数(如果为1则成了一棵树,可以出解了),以及修改了谁的father。
merge操作就是修改这三个东西……
考虑Remove,也就是删掉一条边:
如果最后一次加边并没有修改father,那么直接删就好了……cur--
否则:我们要将这条边断掉,此时由于我们保存了该时刻的边权和以及连通块个数,所以这些都不用考虑修改……唯一需要重新维护的是每个并查集的rank,这里我一开始yy的修改方式是:将从x到其所在并查集的root的rank都减去rank[x]。然而这样TLE了……FST了最后一个点(非常鬼畜,加一条边,减一条边,加两条边,减两条边……)一开始我以为是需要卡常数,照着神犇的代码一点一点改……然而其实是这里出了问题:每次要将这一条链上的每个点 i 的rank[fa[i]]-=rank[i]。(目前百思不得其解,留一个坑吧)
这里我们离线做,做完一个操作后先读一下,看下下一个操作是不是Remove,如果是就直接执行。(这里我的感觉是为了方便知道要撤销的操作是什么)
UPD:2015年6月24日 09:06:56(Orz zyf)
其实是由于循环条件写的是i!=fa[i],然后我每次修改的是rank[i]-=rank[x],所以会导致根那个点(i==fa[i])没有修改……改成每次修改rank[fa[i]]-=rank[x]就可以了
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]) swap(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[x]; 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 }