标签:tar 接下来 blog sdi 假设 cpp tchar amp 随机化算法
原文链接www.cnblogs.com/zhouzhendong/p/UOJ75.html
根本没想到。
首先我们可以考虑一种做法:
找一些图,使得他们各自的生成树个数乘起来等于 k。
那么只要将他们用一条链连起来就得到答案了。
接下来考虑如何得到这些图。
考虑随机生成一个 n 个点的图,它的生成树个数最大是 $n^{n-2}$ 。
我们假装一个 n 个点的图的生成树个数是 $[0,n^{n-2}]$ 中的随机数。
假设我们随机生成了 S 个这样的图,如果我们在这 S 个图中随机选择 t 个连起来,那么我们就得到了 $S^t$ 个随机数。
令 n = 12, S = 1000, t = 4,由于 $n^{n-2} = 12^{10}> 62\cdot 998244353$,所以我们可以在对 998244353 取模之后把生成树个数当作一个 $[0,998244353)$ 中的随机数。则我们得到了 $S^t = 10^{12}$ 个随机数。这 $10^{12}$ 个数中不含有 k 个概率非常小。
我们不可能把所有所有的这些随机数都求出来,所以我们用类似于 BSGS 的办法折半一下就好了。
#pragma GCC optimize("Ofast","inline") #include <bits/stdc++.h> #define clr(x) memset(x,0,sizeof (x)) #define For(i,a,b) for (int i=a;i<=b;i++) #define Fod(i,b,a) for (int i=b;i>=a;i--) #define pb(x) push_back(x) #define mp(x,y) make_pair(x,y) #define fi first #define se second #define _SEED_ (‘C‘+‘L‘+‘Y‘+‘A‘+‘K‘+‘I‘+‘O‘+‘I‘) #define outval(x) printf(#x" = %d\n",x) #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("") #define outtag(x) puts("----------"#x"----------") #define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R); For(_v2,L,R)printf("%d ",a[_v2]);puts(""); using namespace std; typedef long long LL; typedef vector <int> vi; LL read(){ LL x=0,f=0; char ch=getchar(); while (!isdigit(ch)) f|=ch==‘-‘,ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return f?-x:x; } const int N=1005,M=20,mod=998244353; void Add(int &x,int y){ if ((x+=y)>=mod) x-=mod; } void Del(int &x,int y){ if ((x-=y)<0) x+=mod; } int Pow(int x,int y){ int ans=1; for (;y;y>>=1,x=(LL)x*x%mod) if (y&1) ans=(LL)ans*x%mod; return ans; } vector <pair <int,int> > g[N]; int val[N],ival[N]; int calc(int n,vector <pair <int,int> > &e){ static int a[M][M]; clr(a); for (auto E : e){ int x=E.fi,y=E.se; a[x][y]++,a[y][x]++; a[x][x]--,a[y][y]--; } For(i,1,n) For(j,1,n) if (a[i][j]<0) a[i][j]+=mod; n--; For(i,1,n){ For(j,i,n) if (a[j][i]!=0){ For(k,i,n) swap(a[i][k],a[j][k]); break; } if (a[i][i]==0) return 0; For(j,i+1,n){ int v=(LL)a[j][i]*Pow(a[i][i],mod-2)%mod; For(k,i,n) Del(a[j][k],(LL)a[i][k]*v%mod); } } int ans=mod-1; For(i,1,n) ans=(LL)ans*a[i][i]%mod; return ans; } struct hash_map{ static const int Ti=233,mod=1<<20; int cnt,k[mod+1],v[mod+1],nxt[mod+1],fst[mod+1]; int Hash(int x){ int v=x&(mod-1); return v==0?mod:v; } void clear(){ cnt=0; memset(fst,0,sizeof fst); } void update(int x,int a){ int y=Hash(x); for (int p=fst[y];p;p=nxt[p]) if (k[p]==x){ v[p]=a; return; } k[++cnt]=x,nxt[cnt]=fst[y],fst[y]=cnt,v[cnt]=a; return; } int find(int x){ int y=Hash(x); for (int p=fst[y];p;p=nxt[p]) if (k[p]==x) return v[p]; return 0; } int &operator [] (int x){ int y=Hash(x); for (int p=fst[y];p;p=nxt[p]) if (k[p]==x) return v[p]; k[++cnt]=x,nxt[cnt]=fst[y],fst[y]=cnt; return v[cnt]=0; } }Map; int S=1000; void prework(){ srand(_SEED_); int n=12; For(i,1,S){ For(j,1,n) For(k,1,j-1) if (rand()%10>=2) g[i].pb(mp(j,k)); val[i]=calc(n,g[i]); ival[i]=Pow(val[i],mod-2); } Map.clear(); For(i,1,S) For(j,1,i){ int tmp=(LL)val[i]*val[j]%mod; Map[tmp]=i*(S+1)+j; } } void solve(int x){ if (!x) return (void)puts("2 0"); For(i,1,S) For(j,1,i){ int tmp=(LL)x*ival[i]%mod*ival[j]%mod; if (Map[tmp]){ int v[4]={i,j,Map[tmp]/(S+1),Map[tmp]%(S+1)}; vector <pair <int,int> > res; res.clear(); int n=48,cnt=0; For (k,0,3){ if (cnt>0) res.pb(mp(cnt,cnt+1)); for (auto e : g[v[k]]) res.pb(mp(e.fi+cnt,e.se+cnt)); cnt+=12; } printf("%d %d\n",n,(int)res.size()); for (auto e : res) printf("%d %d\n",e.fi,e.se); return; } } } int main(){ prework(); int T=read(); while (T--) solve(read()); return 0; }
UOJ#75. 【UR #6】智商锁 随机化算法 矩阵树定理
标签:tar 接下来 blog sdi 假设 cpp tchar amp 随机化算法
原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ75.html