zoukankan      html  css  js  c++  java
  • UOJ#75. 【UR #6】智商锁 随机化算法 矩阵树定理

    原文链接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}> 62cdot 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
    ",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,(int)res.size());
    				for (auto e : res)
    					printf("%d %d
    ",e.fi,e.se);
    				return;
    			}
    		}
    }
    int main(){
    	prework();
    	int T=read();
    	while (T--)
    		solve(read());
    	return 0;
    }
    

      

  • 相关阅读:
    什么是模块化及其优点是什么
    oop的三大特性和传统dom如何渲染
    MVC和MVVM的差别
    SpringMVC实例及注解(二)
    Spring MVC实例创建(一)
    Mybatis联合查询(一)
    Mybatis参数传递及返回类型
    Mybatis实例增删改查(二)
    Mybatis实例及配置(一)
    SpringMVC
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ75.html
Copyright © 2011-2022 走看看