模拟赛2021.4.5

2021.4.5模拟赛

T1

题意:给定有\(n\)点的完全图,每次删去图中一个三元环,求方案使得剩下的边数严格小于\(n\)

神仙构造题

我们考虑每组满足\(x+y+z\equiv 0 \pmod n(x\not =y)\)构成的三元环

显然,对于每个\(x,y\)对应的\(z\)是唯一的

问题在于\(x+y+x\equiv 0\pmod n\)的情况

\(\Rightarrow 2x\equiv n-y\pmod n\)

  1. \(2\mid n\).则对于\(2\nmid y\),\(x\)无解.对于\(2\mid y\),\(2x=y\)\(2x=y+n\),至多\(n-2\)个.(\(n=x\)时无解)
  2. \(2\nmid n\).\(2\)\(n\)意义下存在逆元,\(x\)唯一对应\(y\),至多\(n-1\)个.(\(n=x\)时无解)
#include<bits/stdc++.h>
using namespace std;
# define ll long long
# define read read1<ll>()
# define Type template<typename T>
Type T read1(){
	T t=0;char k;bool vis=0;
	do (k=getchar())=='-'&&(vis=1);while('0'>k||k>'9');
	while('0'<=k&&k<='9')t=(t<<3)+(t<<1)+(k^'0'),k=getchar();
	return vis?-t:t;
}
# define fre(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)
int s,tot;
pair<int,pair<int,int> >a[1000005];
int main(){fre("circle");
	s=read;
	for(int i=1;i<s;++i)
		for(int j=i+1;j<=s;++j)
			if(s-(i+j)%s>j)
				a[++tot]=make_pair(i,make_pair(j,s-(i+j)%s));
	puts("Yes");cout<<tot<<endl;
	for(int i=1;i<=tot;++i)
		printf("%d %d %d\n",a[i].first,a[i].second.first,a[i].second.second);
	return 0;
}

T2

题意:求出字符串中本质不同的子串个数,字符串中只有前\(m\)个小写字母

当且仅当两个长度均为\(n\)字符串\(S,T\).\(\forall{i\in[0,n-1]},S[i]==T[i]\)时两串本质相同

\(len\leq 5\cdot 10^4,m\leq 10\)

我们先进行一个转换,将字符串\(S\)中的每位转换成这个字符上一次出现的位置离当前位置的距离,如无则为\(0\).设转换后的串为\(A\)

那我们不难发现当转换后的两串相等时则原串本质相同

但如果直接转换后跑\(\tt lcp\)则会出现问题

因为取子串后少了段前缀,\(A\)会发生变化

但我们发现在截取的子串中每种字母只有第一次出现的位置上的\(A\)会变化

所以我们记录下每个后缀中的每种字母第一次出现的位置

\(A\)\(\tt sort\)时特殊考虑每种字母第一次出现的位置,进行比较

当然,我们需要使用\(\tt hash\)\(SA(M)\)预处理,加速我们比较的过程

时间复杂度\(O(nm\log n)\)

#include<bits/stdc++.h>
using namespace std;
# define ll long long
# define read read1<ll>()
# define Type template<typename T>
Type T read1(){
	T t=0;char k;bool vis=0;
	do (k=getchar())=='-'&&(vis=1);while('0'>k||k>'9');
	while('0'<=k&&k<='9')t=(t<<3)+(t<<1)+(k^'0'),k=getchar();
	return vis?-t:t;
}
# define fre(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)
char str[50005];
int s,m,a[50005],sa[50005],rk[50005],tp[50005],h[17][50005],l2[50005];
bool cmp(int x,int y){return rk[x]==rk[y]?tp[x]<tp[y]:rk[x]<rk[y];}
void S_sort(){
	for(int i=1;i<=s;++i)sa[i]=i,rk[i]=a[i],tp[i]=0;
	for(int i=1;i<s;i<<=1){
		for(int j=1;j<=s;++j)
			if(j+i<=s)tp[j]=rk[j+i];
			else tp[j]=0;
		sort(sa+1,sa+s+1,cmp);
		int r=0;
		memcpy(tp,rk,s+1<<2);
		rk[sa[1]]=r=1;
		for(int j=2;j<=s;++j)
			rk[sa[j]]=tp[sa[j]]!=tp[sa[j-1]] or tp[sa[j]+i]!=tp[sa[j-1]+i]?++r:r;
	}
}
void prep(){
	for(int i=1,k=0;i<=s;++i){
		if(rk[i]==s)continue;
		int j=sa[rk[i]+1];
		if(k)--k;
		while(i+k<=s&&j+k<=s&&a[i+k]==a[j+k])++k;
		h[0][rk[i]]=k;
	}
	for(int i=1;(1<<i)<s;++i)
		for(int j=1;j+(1<<i)-1<s;++j)
			h[i][j]=min(h[i-1][j],h[i-1][j+(1<<i-1)]);
}
vector<int>q[50005];
int id[50005];
int Log2(int x){return l2[x];}
int query(int l,int r){
	l=rk[l],r=rk[r];
	if(l>r)swap(l,r);--r;
	int n=Log2(r-l+1);
	return min(h[n][l],h[n][r-(1<<n)+1]);
}int M;
bool cmp1(int x,int y){
	int len=0;
	for(int i=0,j=0;i!=q[x].size()||j!=q[y].size();++i,++j)
		if(i!=q[x].size()&&j!=q[y].size()&&q[x][i]-x==q[y][j]-y){
			int v=query(x+len,y+len);
			if(x+len+v<q[x][i]){M=len+v;return a[x+len+v]<a[y+len+v];}
			len=q[x][i]-x+1;
		}else if(i!=q[x].size()&&(j==q[y].size()||q[x][i]-x<q[y][j]-y)){
			int v=query(x+len,y+len);
			if(x+len+v<q[x][i]){M=len+v;return a[x+len+v]<a[y+len+v];}
			M=q[x][i]-x;return j==q[y].size()?0:1;
		}else{
			int v=query(x+len,y+len);
			if(y+len+v<q[y][j]){M=len+v;return a[x+len+v]<a[y+len+v];}
			M=q[y][j]-y;return i==q[x].size()?1:0;
		}
	M=s-max(x,y)+1;
	return x>y;
}
int main(){fre("string");
	s=read,m=read;
	scanf("%s",str+1);
	for(int i=2;i<=s;++i)l2[i]=l2[i>>1]+1;
	for(int i=1,*t=new int[m]();i<=s;++i){
		if(t[str[i]-'a'])a[i]=i-t[str[i]-'a'];
		else a[i]=0;
		t[str[i]-'a']=i;
		id[i]=i;
	}
	for(int i=s,*t=new int[m]();i;--i){
		t[str[i]-'a']=i;
		for(int j=0;j<m;++j)
			if(t[j])q[i].push_back(t[j]);
		q[i].push_back(s+1);
		sort(q[i].begin(),q[i].end());
	}
	S_sort();prep();
	sort(id+1,id+s+1,cmp1);
	ll ans=1ll*s*(s+1)/2;
	for(int i=1;i<s;++i){
		cmp1(id[i],id[i+1]);
		M=min(M,s-max(id[i],id[i+1])+1);
		ans-=M;
	}cout<<ans;
	return 0;
}

T3

题意:有矩阵\(A\)与置换\(P\),给出\(A_1\).\(A_i\)=\(P(A_{i-1})\),求\(\det(A)\)

\(n\leq 5000\)

不难发现,当置换\(P\)的循环拆分个数大于\(1\)时,答案为\(0\)

不妨设拆分成了\(2\)个循环,为\(x\)\(y\),其中\(|x|\leq |y|\)

则会发现后\(|y|\)行消去前\(|x|\)行后线性相关

大于\(2\)时归纳易证

所以我们现在就是要求一个循环矩阵\(A\)的行列式

\[A=\left[\begin{matrix}a_0&a_1&\cdots&a_{n-1}\\a_{n-1}&a_0&\cdots&a_{n-2}\\\vdots&\vdots&\ddots&\vdots\\a_1&a_2&\cdots&a_0\end{matrix}\right] \]

设矩阵\(C=\left[\begin{matrix}1&1&\cdots&1\\1&\omega^1_n&\cdots&\omega^{n-1}_n\\1&\omega^2_n&\cdots&\omega^{2(n-1)}_n\\\vdots&\vdots&\ddots&\vdots\\1&\omega^{n-1}_n&\cdots&\omega^{(n-1)^2}_n\end{matrix}\right]\)

因为\(C\)为范德蒙矩阵

所以\(\det(C)=\prod_{0\leq i<j<n}(\omega^j-\omega^i)\not =0\)

所以\(C\)为非奇异矩阵

\(f(x)=\sum_{i=0}^{n-1}a_ix^i\)

\[AC=\left[\begin{matrix}f(1)&f(\omega)&f(\omega^2)&\cdots&f(\omega^{n-1})\\ f(1)&\omega f(\omega)&\omega^2 f(\omega^2)&\cdots&\omega^{n-1} f(\omega^{n-1})\\\vdots&\vdots&\vdots&\ddots&\vdots\\f(1)&\omega^{(n-1)} f(\omega)&\omega^{2(n-1)} f(\omega^2)&\cdots&\omega^{(n-1)^2} f(\omega^{n-1})\end{matrix}\right]=\left(\prod_{i=0}^{n-1}f(\omega^i)\right)C\\ \Rightarrow \det(A)\det(C)=\left(\prod_{i=0}^{n-1}f(\omega^i)\right)\det(C)\\ \Rightarrow \det(A)=\prod_{i=0}^{n-1}f(\omega^i) \]

所以怎么求\(\prod_{i=0}^{n-1}f(\omega^i)\)呢?

如果不带模,我们可以直接用离散傅里叶变换

可是带模

我们可以发现,\(\omega^i\)其实就是多项式\(g(x)=x^n-1\)的根

\(\lambda_{0\sim n-1}\)表示\(n\)次多项式\(A\)\(n\)个根

\(\zeta_{0\sim m-1}\)表示\(m\)次多项式\(B\)\(m\)个根

\(A=([x^n]A)\prod_{i=0}^{n-1}(x-\lambda_i)\)

定义函数\(\gamma(A,B)\)表示\(([x^m]B)^n\prod_{i=0}^{m-1}A(\zeta_i)\)

\[\begin{align} \gamma(A,B)&=([x^m]B)^n\prod_{i=0}^{m-1}A(\zeta_i)\\ &=([x^m]B)^n\prod_{i=0}^{m-1}([x^n]A)\prod_{j=0}^{n-1}(\zeta_i-\lambda_j)\\ &=([x^m]B)^n([x^n]A)^m\prod_{i=0}^{m-1}\prod_{j=0}^{n-1}(\zeta_i-\lambda_j)\\ &=(-1)^{nm}([x^n]A)^m\prod_{i=0}^{n-1}B(\lambda_i)\\ &=(-1)^{nm}\gamma(B,A) \end{align} \]

\[\begin{align} \gamma(A-B,B)&=([x^m]B)^n\prod_{i=0}^{m-1}(A(\zeta_i)-B(\zeta_i))\\ &=([x^m]B)^n\prod_{i=0}^{m-1}A(\zeta_i)\\ &=\gamma(A,B) \end{align} \]

\[\gamma(A,B)=A^m(A为常函数) \]

\[\begin{align} \gamma(kA,B)&=([x^m]B)^n\prod_{i=0}^{m-1}kA(\zeta_i)\\ &=([x^m]B)^nk^m\prod_{i=0}^{m-1}A(\zeta_i)\\ &=k^m\gamma(A,B) \end{align} \]

同理\(\gamma(A,kB)=(-1)^{nm}\gamma(kB,A)=k^n\gamma(A,B)\)

这样我们就可以像\(\tt gcd\)一样在\(O(n^2)\)的时间内求出来了

#include<bits/stdc++.h>
using namespace std;
# define ll long long
# define read read1<ll>()
# define Type template<typename T>
Type T read1(){
	T t=0;char k;bool vis=0;
	do (k=getchar())=='-'&&(vis=1);while('0'>k||k>'9');
	while('0'<=k&&k<='9')t=(t<<3)+(t<<1)+(k^'0'),k=getchar();
	return vis?-t:t;
}
# define fre(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)
# define mod 1000000007
int s,q[5005],a[5005],b[5005];
ll qkpow(ll n,int m){
	ll t=1;
	for(;m;m>>=1,n=n*n%mod)
		if(m&1)t=t*n%mod;
	return t;
}
int main(){fre("matrix");
	s=read;
	for(int i=1;i<=s;++i)a[i]=read;
	for(int i=1;i<=s;++i)q[read]=i;
	for(int i=1,t=1;t<=s;++t,i=q[i]){
		if(i==1&&t!=1)return puts("0"),0;
		b[t]=i;
	}ll ans=1;
	for(int i=1;i<=s;b[i-1]=a[b[i]],++i)
		for(int j=i+1;j<=s;++j)
			if(b[i]>b[j])
				ans=-ans;
	memset(a,0,sizeof(a));
	int n=s,m=s-1;
	a[n]=1;a[0]=-1;
	while(1){
		if(n<m)swap(n,m),(n&m&1)&&(ans=-ans),swap(a,b);
		if(!m){
			ans=ans*qkpow(b[0],n)%mod;
			break;
		}
		for(int i=n-m;~i;--i){
			if(!a[i+m])continue;
			ll x=qkpow(b[m],mod-2)*a[i+m]%mod;
			for(int j=0;j<=m;++j)
				a[i+j]=(a[i+j]-b[j]*x)%mod;
		}
		int tv=n;
		while(!a[n]&&n)--n;
		ans=ans*qkpow(b[m],tv-n)%mod;
	}printf("%lld",(ans+mod)%mod);
	return 0;
}
posted @ 2021-04-05 19:23  ファイナル  阅读(122)  评论(1编辑  收藏  举报