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}> 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;
}

  

原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ75.html

时间: 2024-11-01 12:59:03

UOJ#75. 【UR #6】智商锁 随机化算法 矩阵树定理的相关文章

【算法】Matrix - Tree 矩阵树定理 &amp; 题目总结

最近集中学习了一下矩阵树定理,自己其实还是没有太明白原理(证明)类的东西,但想在这里总结一下应用中的一些细节,矩阵树定理的一些引申等等. 首先,矩阵树定理用于求解一个图上的生成树个数.实现方式是:\(A\)为邻接矩阵,\(D\)为度数矩阵,则基尔霍夫(Kirchhoff)矩阵即为:\(K = D - A\).具体实现中,记 \(a\) 为Kirchhoff矩阵,则若存在 \(E(u, v)\) ,则\(a[u][u] ++, a[v][v] ++, a[u][v] --, a[v][u] --\

@算法 - [email&#160;protected] matrix - tree 定理(矩阵树定理)

目录 @0 - 参考资料@ @0.5 - 你所需要了解的线性代数知识@ @1 - 定理主体@ @证明 part - [email protected] @证明 part - [email protected] @证明 part - [email protected] @证明 part - 4@ @2 - 一些简单的推广@ @3 - 例题与应用@ @0 - 参考资料@ MoebiusMeow 的讲解(超喜欢这个博主的!) 网上找的另外一篇讲解 @0.5 - 你所需要了解的线性代数知识@ 什么是矩阵

POJ 3318 Matrix Multiplication(随机化算法)

给你三个矩阵A,B,C.让你判断A*B是否等于C. 随机一组数据,然后判断乘以A,B之后是否与乘C之后相等. 很扯淡的啊,感觉这种算法不严谨啊... Matrix Multiplication Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 16255   Accepted: 3515 Description You are given three n × n matrices A, B and C. Does the e

PKU 2531 Network Saboteur(dfs+剪枝||随机化算法)

题目大意:原题链接 给定n个节点,任意两个节点之间有权值,把这n个节点分成A,B两个集合,使得A集合中的每一节点与B集合中的每一节点两两结合(即有|A|*|B|种结合方式)权值之和最大. 标记:A集合:true  B集合:false 解法一:dfs+剪枝 #include<iostream> #include<cstring> using namespace std; int n,ans; bool in[25]; int graph[25][25]; void dfs(int i

POJ3318--Matrix Multiplication 随机化算法

Description You are given three n × n matrices A, B and C. Does the equation A × B = C hold true? Input The first line of input contains a positive integer n (n ≤ 500) followed by the the three matrices A, B and C respectively. Each matrix's descript

快速排序的随机化算法

快速排序在最坏情况下的复杂度较高,采取随机化算法选择每次的分割点,能够在一定程度上使每次划分的平衡性更好. // // main.cpp // eoj1807 // // Created by Fangpin on 15/3/15. // Copyright (c) 2015年 FangPin. All rights reserved. // #include <iostream> #include <cstdlib> #include <cstdio> #includ

加锁并发算法 vs 无锁并发算法

Heinz Kabutz 在上周举办了一次成功 JCrete研讨会,我在会上参加了对一种新的 StampedLock(于JSR166中 引入) 进行的评审.StampedLock (邮戳锁) 旨在解决系统中共享资源的争用问题.在一个系统中,如果多个需要读写某一共享状态的程序并发访问这个共享对象时,争用问题就产生了.在设计 上,StampedLock 试图通过一种“乐观读取”的方式来减小系统开销,从而提供比 ReentrantReadWriteLock(重入读写锁) 更好的性能. 在评审过程中,我

[ACM] POJ 3318 Matrix Multiplication (随机化算法)

Matrix Multiplication Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 16118   Accepted: 3485 Description You are given three n × n matrices A, B and C. Does the equation A × B = C hold true? Input The first line of input contains a posit

算法14---B树

算法14---B树 更详细的讲解见http://www.xuebuyuan.com/509072.html 一棵m阶的B 树 (m叉树)的特性,如下: (1)树中每个结点含有最多含有个孩子,即m满足:ceil(m/2)-1<=n<=m-1. (2)除根结点和叶子结点外,其它每个结点至少有[ceil(m / 2)]个孩子(其中ceil(x)是一个取上限的函数): (3)若根结点不是叶子结点,则至少有2个孩子(特殊情况:没有孩子的根结点,即根结点为叶子结点,整棵树只有一个根节点): 1.1.插入(