这场除了套路题就是科技题非常无语
T1 菜道路
赛时写的\(n^4\)暴力过掉了,好卡但也不好卡,正解就是把枚举边直接换成Floyd判就是\(n^3\)的了
点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i)
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
#define int ll
using namespace std;
const int maxn=3e2+10;
int dis[maxn][maxn];
int now[maxn][maxn];
int n;
ll ans=0;
struct EDGE{
int x,y,dis;
bool operator <(const EDGE & rhs)const{return dis<rhs.dis;}
};
vector<EDGE>vec;
void solve(){
cin>>n;
Rep(i,1,n)Rep(j,1,n)cin>>dis[i][j];
Rep(k,1,n)Rep(i,1,n)if(i!=k)Rep(j,1,n)if(i!=j && j!=k)
if(dis[i][k]+dis[k][j]<dis[i][j])
return cout<<"-1\n",void();
Rep(i,1,n)Rep(j,i+1,n)vec.push_back(EDGE{i,j,dis[i][j]});
sort(vec.begin(),vec.end());
memset(now,0x3f,sizeof(now));
Rep(i,1,n)now[i][i]=0;
for(auto it : vec){
if(now[it.x][it.y]==dis[it.x][it.y])continue;
ans+=it.dis;
now[it.x][it.y]=now[it.y][it.x]=it.dis;
Rep(i,1,n)Rep(j,1,n)
now[i][j]=min(now[i][j],min(now[i][it.x]+it.dis+now[it.y][j],now[i][it.y]+it.dis+now[it.x][j]));
}
cout<<ans<<"\n";
}
#undef int
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }
T2 简单环
套路建搜索树,只会出现返祖边,一组边有贡献当且仅当他们被同一条返祖边恰好覆盖了一次,树上差分判一下就是\(O(n)\)的,可以开到\(1e6\)
点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i)
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;
const int maxn=1e5+10,maxm=5e5+10;
int n,m;
map<pii,int>Map;
vector<int>ans;
struct Graph{
struct eg{int from,to,next;}e[maxm];
int len,head[maxn];int fa[maxn];
int Root;
vector<int>son[maxn],gr[maxn];
void lqx(int from,int to)
{ e[++len].from=from,e[len].to=to,e[len].next=head[from],head[from]=len; }
int pre[maxn],val[maxn]; bool vis[maxn];int dep[maxn];
void Dfs1(int u,int f){
vis[u]=true;dep[u]=dep[f]+1;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;if(v==f)continue;
if(!vis[v])Dfs1(v,u),val[u]+=val[v],son[u].push_back(v),fa[v]=u;
else if(dep[u]>dep[v])
val[u]++,val[v]--,gr[u].push_back(v);
}
}
void Dfs2(int u){
pre[u]=(val[u]==1)+pre[fa[u]];
for(auto v : gr[u])if(pre[u]-pre[v]==dep[u]-dep[v]){
ans.push_back(Map[minmax(u,v)]);
int now=u,pt=fa[u];
while(now!=v){ ans.push_back(Map[minmax(now,pt)]); now=pt,pt=fa[pt]; }
}
for(auto v : son[u])Dfs2(v);
}
}G;
void solve(){
cin>>n>>m;int x,y;
Rep(i,1,m){ cin>>x>>y; G.lqx(x,y),G.lqx(y,x);Map[minmax(x,y)]=i; }
Rep(i,1,n)if(!G.vis[i]){ G.Dfs1(i,0);G.Dfs2(i); }
cout<<ans.size()<<"\n";
sort(ans.begin(),ans.end());
for(auto it : ans)cout<<it<<" ";
}
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }
T3 汉明距离
科技题,考虑如果算出不同的两位的贡献,其实就是\((a_i-b_i)^2\),这一点比较秒,然后就是随便卷一卷了
\[ H(x)=\sum_{i=0}^{m}F_{i+x} G_i
\]
\(x\) 即偏移量,为啥一秒能做\(1e6\)的NTT
点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i)
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define cp complex<double>
#define fir first
#define sec second
#define int ll
using namespace std;
const int maxn=4e6+10,Mod=998244353;
int pw(int x,int p){int res=1,base=x;while(p){if(p&1)res=1LL*res*base%Mod;base=1LL*base*base%Mod;p>>=1;}return res;}
int Inv(int x){return pw(x,Mod-2);}
int W[maxn],Cw[maxn],rev[maxn];
int deg,lg;
void Init(int len){
deg=1,lg=0;while(deg<len)deg<<=1,++lg;
W[0]=Cw[0]=1;int Wp=pw(3,(Mod-1)/deg),Cp=pw(Inv(3),(Mod-1)/deg);
for(int i=1;i<deg;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1)),W[i]=1LL*W[i-1]*Wp%Mod,Cw[i]=1LL*Cw[i-1]*Cp%Mod;
}
bool op;
struct Poly{
vector<int>f;
int &operator[](const int &i){return f[i];}
int operator[](const int &i)const{return f[i];}
int Deg(){return f.size();}
int Deg()const{return f.size();}
void Set(int len){f.resize(len);}
void Adjust(){while(f.size()>1 && f.back()==0)f.pop_back();}
void Print(){for(auto it : f)cerr<<it<<" ";cerr<<"\n";}
void NTT(int deg,int w[],int opt){
Set(deg);for(int i=0;i<deg;++i)if(i<rev[i])swap(f[i],f[rev[i]]);
for(int t=deg>>1,m=1;m<deg;m<<=1,t>>=1)for(int i=0;i<deg;i+=(m<<1))for(int j=0;j<m;++j)
{ int x=f[i+j],y=1LL*w[t*j]*f[i+j+m]%Mod;f[i+j]=(x+y)%Mod,f[i+j+m]=(x-y+Mod)%Mod;}
if(opt==-1 && op==false){int inv=::Inv(deg);for(int i=0;i<deg;++i)f[i]=1LL*f[i]*inv%Mod;}
}
friend Poly operator * (const Poly &x,const Poly &y){
Poly res,A=x,B=y;
Init(A.Deg()+B.Deg()-1);
A.NTT(deg,W,1);op=true;B.NTT(deg,Cw,-1);op=false;res.Set(deg);
for(int i=0;i<deg;++i)res[i]=1LL*A[i]*B[i]%Mod;
res.NTT(deg,Cw,-1);res.Adjust();
return res;
}
void operator *= (const Poly &x){
Poly A=x;
Init(Deg()+A.Deg()-1);
NTT(deg,W,1),A.NTT(deg,W,1);
for(int i=0;i<deg;++i)f[i]=1LL*f[i]*A[i]%Mod;
NTT(deg,Cw,-1);Adjust();
}
}F,G;
int n,m;
char s[maxn>>1],t[maxn>>1];
int prea[maxn>>1],preb[maxn>>1];
void solve(){
cin>>s>>t;
int n=strlen(s),m=strlen(t);
F.Set(n),G.Set(m);
for(int i=0;i<n;++i)F[i]=(s[i]-'0'),prea[i]=prea[max(i-1,0LL)]+(s[i]-'0');
for(int i=0;i<m;++i)G[i]=(t[i]-'0'),preb[i]=preb[max(i-1,0LL)]+(t[i]-'0');
F=F*G;
int ans=m;
for(int i=0;i+m-1<n;++i){
if(i>0)ans=min(ans,(prea[i+m-1]-prea[i-1]+preb[m-1]-2*F[i]+Mod)%Mod);
else ans=min(ans,(prea[i+m-1]+preb[m-1]-2*F[i]+Mod)%Mod);
}
cout<<(ans%Mod+Mod)%Mod<<"\n";
}
#undef int
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }
T4 勇者的后缀
后缀数组的题,一看后缀LCP字典序这必后缀数组啊,管他noip不noip的
根据后缀数组的结论,对于一组询问\(x,l,r\),我们可以找到后缀\(x\)在\([l,r]\)内排名的前驱后继,\(x\)与两者的\(LCP\)取\(\max\)就是第一问的答案。由于\(high\)数组上取\(\min\)的单调性,能够得到这个长度的\(LCP\)的后缀的排名一段连续的区间,二分找到这个区间的左界,然后找到大于等于左界且小于后缀\(x\)的在区间出现过的最小排名即可,大于\(x\)的显然一定是后继最优。对于查前驱后继和最小,可以用值域主席树,由于是同时区间和值域的,所以我只会暴力查排名再查第\(K\)大,有没有巨佬教教我怎么查前驱后继。
点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i)
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;
const int maxn=2e5+10,INF=20051107;
int rk[maxn],sec[maxn],sa[maxn],tub[maxn],heg[maxn];
int st[maxn][19],lg[maxn];
int n,M=200,m;
char s[maxn];
int root[maxn];
struct ZXS{
#define LCH tr[rt].lch
#define RCH tr[rt].rch
struct Tree{ int lch,rch,sum; }tr[maxn*40];
int tot;
void Pushup(int rt){ tr[rt].sum=tr[LCH].sum+tr[RCH].sum; }
void Modify(int &rt,int p,int l,int r,int x,int w){
if(!rt)rt=++tot,tr[rt]=tr[p];
if(l==r)return tr[rt].sum=w,void();
int mid=(l+r)>>1;
if(x<=mid){ LCH=0;Modify(LCH,tr[p].lch,l,mid,x,w); }
else { RCH=0;Modify(RCH,tr[p].rch,mid+1,r,x,w); }
Pushup(rt);
}
/*int QueryMin(int rt,int p,int l,int r,int s,int t){
if(t<s)return INF;
if(!rt)return INF;
if(tr[rt].sum-tr[p].sum==0)return INF;
if(l==r)return l;
int mid=(l+r)>>1;
int res=INF;
if(s<=mid && (tr[LCH].sum-tr[tr[p].lch].sum))res=QueryMin(LCH,tr[p].lch,l,mid,s,t);
if(res!=INF)return res;
if(t>mid && (tr[RCH].sum-tr[tr[p].rch].sum))return QueryMin(RCH,tr[p].rch,mid+1,r,s,t);
return INF;
}
int QueryMax(int rt,int p,int l,int r,int s,int t){
if(t<s)return INF;
if(!rt)return INF;
if(tr[rt].sum-tr[p].sum==0)return INF;
if(l==r)return l;
int mid=(l+r)>>1;
int res=INF;
if(t>mid && (tr[RCH].sum-tr[tr[p].rch].sum))return QueryMax(RCH,tr[p].rch,mid+1,r,s,t);
if(res!=INF)return res;
if(s<=mid && (tr[LCH].sum-tr[tr[p].lch].sum))return QueryMax(LCH,tr[p].lch,l,mid,s,t);
return INF;
}*/
int Rank(int rt,int p,int l,int r,int x){
if(!rt)return 0;
if(tr[rt].sum-tr[p].sum==0)return 0;
if(l==r)return 0;
int mid=(l+r)>>1;
if(x<=mid)return Rank(LCH,tr[p].lch,l,mid,x);
else return (tr[LCH].sum-tr[tr[p].lch].sum)+Rank(RCH,tr[p].rch,mid+1,r,x);
}
int Kth(int rt,int p,int l,int r,int x){
if(l==r)return l;
int mid=(l+r)>>1;
int lsum=(tr[LCH].sum-tr[tr[p].lch].sum);
if(lsum>=x)return Kth(LCH,tr[p].lch,l,mid,x);
else return Kth(RCH,tr[p].rch,mid+1,r,x-lsum);
}
}T;
void SA(){
Rep(i,1,n)++tub[rk[i]=s[i]],lg[i]=lg[i>>1]+1;
Rep(i,1,M)tub[i]+=tub[i-1];
Dwn(i,n,1)sa[tub[rk[i]]--]=i;
for(int w=1;;w<<=1){
int p=0;
Rep(i,n-w+1,n)sec[++p]=i;
Rep(i,1,n)if(sa[i]>w)sec[++p]=sa[i]-w;
Rep(i,1,M)tub[i]=0;
Rep(i,1,n)++tub[rk[i]];
Rep(i,1,M)tub[i]+=tub[i-1];
Dwn(i,n,1)sa[tub[rk[sec[i]]]--]=sec[i],sec[i]=0;
swap(rk,sec);
rk[sa[1]]=1,p=1;
Rep(i,2,n)rk[sa[i]]=(sec[sa[i]]==sec[sa[i-1]] && sec[sa[i]+w]==sec[sa[i-1]+w]) ? p : ++p;
if(p==n)break;
M=p;
}int k=0;
for(int i=1;i<=n;i++){
if(rk[i]==1)continue;
if(k)--k;
while(s[i+k]==s[sa[rk[i]-1]+k])++k;
heg[rk[i]]=k;
}
Rep(i,1,n)st[i][0]=heg[i];
Rep(j,1,18)Rep(i,1,n-(1<<j)+1)st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
Rep(i,1,n)T.Modify(root[i],root[i-1],1,n,rk[i],1);
/* cerr<<"Sort::\n";
Rep(i,1,n){
cerr<<sa[i]<<":";
Rep(j,sa[i],n)cerr<<s[j]<<" ";
cerr<<"\n";
}
cerr<<"Finished\n";
*/
}
int Get(int l,int r){++l;int len=lg[r-l+1]-1;return min(st[l][len],st[r-(1<<len)+1][len]);}
pii Sol(int x,int l,int r){
pii res=mair(-1,0);
if(x>=l && x<=r)res=mair(n-x+1,rk[x]);
/* int cnt=0;
Rep(i,l,r)if(i!=x){
pii it=mair(min(rk[x],rk[i]),max(rk[x],rk[i]));
int len=Get(it.fir,it.sec);
cnt+=(rk[i]<rk[x]);
if(len>res.fir)res=mair(len,rk[i]);
else if(len==res.fir && rk[i]<res.sec)
res=mair(len,rk[i]);
}*/
int kx=T.Rank(root[r],root[l-1],1,n,rk[x]);
// cerr<<kx<<" "<<cnt<<"\n";
if(kx>0){
int a=T.Kth(root[r],root[l-1],1,n,kx);
int len=Get(a,rk[x]);
if(len>=res.fir){
int pl=0,pr=a;
while(pr-pl>1){ int mid=(pl+pr)>>1; if(Get(mid,rk[x])==len)pr=mid; else pl=mid; }
a=T.Kth(root[r],root[l-1],1,n,T.Rank(root[r],root[l-1],1,n,pr)+1);
if(len>res.fir)res=mair(len,a);
else res.sec=min(res.sec,a);
}
}
int tim=1+(x>=l && x<=r);
if(kx+tim<=r-l+1){
int a=T.Kth(root[r],root[l-1],1,n,kx+tim);
int len=Get(rk[x],a);
if(len>res.fir)res=mair(len,a);
else if(len==res.fir)res.sec=min(res.sec,a);
}
return res;
}
void solve(){
fre(T4);
cin>>(s+1);n=strlen(s+1); SA();
cin>>m;
while(m--){
int x,l,r;pii res;
cin>>x>>l>>r;
res=Sol(x,l,r);
cout<<res.fir<<" "<<sa[res.sec]<<"\n";
}
}
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }