模拟赛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\)
- \(2\mid n\).则对于\(2\nmid y\),\(x\)无解.对于\(2\mid y\),\(2x=y\)或\(2x=y+n\),至多\(n-2\)个.(\(n=x\)时无解)
- \(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\)的行列式
设矩阵\(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\)
所以怎么求\(\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)\)
同理\(\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;
}
浮世苍茫,不过瞬逝幻梦
善恶爱诳,皆有定数
于命运之轮中
吞噬于黄泉之冥暗
呜呼,吾乃梦之戍人
幻恋之观者
唯于万华镜中,永世长存