郑州寄 8.6
前言
业精于勤荒于嬉,行成于思毁于随
正文(模拟赛)
卦象:凶(忘记起卦了……把 luogu 卦象赫过来)
感受:整个人都不好了。先开的 T1,然而不会,整个人直接裂开,卡了快 40min。然后开 T2,幸运地,T2 一眼秒掉了,然后由于抄式子过程中不等号写反了(最可恨的是两个小样例都能过),调了足足两个点。开 T3,显然字符串这种东西这辈子不可能写的。尽管知道它是 Manacher,尽管知道这玩意很像海亮那天讲的一个题,尽管知道维护一下哈希丢到字典树上基本上就差不多了,但根本就不敢写。因为不熟练的算法真的不敢考场上写,T4 瞄了一眼,悬着的心终于死了。三个点过去了,只获得了 100pts。咋办捏,只能回去开 T1,观测到了好多好多的性质,然而没有通往正解的道路。T1 不想去打暴力,因为暴力实在是没什么含金量,显然只有切掉才能获得一个可观的分数。然而,上天没有站在我这边,最后还是没有会 T1。静等讲题了……
隔壁软软秒了前三题,还有时间打对拍,真是菜完了
好的,好的,好的,原来 T1 是 rz 题,全世界只有云落不会 T1 的情况达成了
T1
唉,证不出来 \(ans \neq 2\) 的蒟蒻
题意
给定三个长度均为 \(n\) 的仅由小写字母构成的字符串 \(a,b,c\),试着找出两个数 \(i,j\) 满足 \(1 <= i < j < n\) 使得以下表达式最小,并输出这个最小值:
题解
赛场上观察到了答案为 \(0,1,2,3\),然而一直卡在怎么判断 \(1,2\)
如果存在 \(a,b\) 首个字符不同位置,那么直接钦定 \(b\) 的长度为 \(1\),在后面找合法的 \(c\) 即可
(找到答案就是 \(0\),找不到自然就是 \(1\) 咯!)
如果 \(b\) 总是和 \(a\) 的首字符相同,那么直接钦定 \(c\) 的字符长度为 \(1\),显然如果 \(c\) 和 \(a,b\) 没有 LCP,答案为 \(1\),否则答案为 \(3\)
代码
短的一匹
点击查看代码
#include<bits/stdc++.h>
#define vi vector<int>
#define pb push_back
using namespace std;
const int N=1e5+5;
int n,f[N][27];char a[N],b[N],c[N];
vi vec;
inline int cal(){
for(int i=2;i<=n-1;i++)
if(b[i]!=a[1])vec.pb(i);
if(!vec.size()){
for(int i=2;i<=n-1;i++)
if(b[i]!=c[i+1])return 1;
return 3;
}
for(int i=n;i>=3;i--){
for(int x=0;x<=25;x++)f[i][x]=f[i+1][x];
f[i][c[i]-'a']++;
}
// for(int i=3;i<=n;i++){
// cerr<<"Zyx "<<i<<": ";
// for(int x=0;x<=25;x++){
// if(f[i][x]!=0){
// cerr<<(char)(x+'a')<<"->"<<f[i][x]<<' ';
// }
// }
// cerr<<endl;
// }
for(int p:vec){
for(int x=0;x<=25;x++){
char ch=(char)(x+'a');
if(ch==b[p]||ch==a[1])continue;
if(f[p+1][x]>0)return 0;
}
}
return 1;
}
inline void solve(){
cin>>n>>(a+1)>>(b+1)>>(c+1);
cout<<cal()<<'\n';
return;
}
int main(){
freopen("lcp.in","r",stdin);
freopen("lcp.out","w",stdout);
int T;cin>>T;while(T--)solve();
return 0;
}
T2
场切了,不嘻嘻
题意

题解
重排方式等价于 title
剩下的部分就是二维数点板子
代码
赛时调了两个点
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int n,cnt1,cnt2;
struct node{int a,b;}p[N];
inline bool cmp(node s,node t){
if(s.a!=t.a)return s.a<t.a;
return s.b>t.b;
}
struct BIT{
int c[N];
inline int lb(int x){return x&(-x);}
inline void clr(){
for(int i=1;i<N;i++)c[i]=0;
return;
}
inline void add(int x,int v){
for(int i=x;i<N;i+=lb(i))c[i]+=v;
return;
}
inline int ask(int x){
int res=0;
for(int i=x;i;i-=lb(i))res+=c[i];
return res;
}
inline int qry(int l,int r){return ask(r)-ask(l-1);}
}bit,B,cnt;
inline int cal1(int i,int j){
if(p[i].a>=p[j].a)return (p[i].b-p[j].b);
return 0;
}
inline int cal2(int i,int j){
if(p[i].a<p[j].a)return (p[i].b-p[j].b);
if(p[i].a==p[j].a)return (p[i].b-p[j].b)*(p[i].b-p[j].b);
return 0;
}
signed main(){
freopen("perm.in","r",stdin);
freopen("perm.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>p[i].a>>p[i].b;
sort(p+1,p+n+1,cmp);
// for(int i=1;i<=n;i++)cerr<<p[i].a<<' '<<p[i].b<<endl;
// int ans=0;
// for(int i=1;i<=n;i++)for(int j=1;j<=i-1;j++)ans+=cal1(i,j);
// for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)ans+=cal2(i,j);
int ans=0;
for(int i=1;i<=n;i++){
ans+=(i-1)*p[i].b;
ans-=bit.ask(p[i].a);
bit.add(p[i].a,p[i].b);
}
for(int i=n;i>=1;i--){
ans+=cnt.qry(p[i].a+1,N-1)*p[i].b;
ans-=B.qry(p[i].a+1,N-1);
B.add(p[i].a,p[i].b);
cnt.add(p[i].a,1);
}
bit.clr();B.clr();cnt.clr();
for(int i=n;i>=1;i--){
ans+=cnt.qry(p[i].a,p[i].a)*p[i].b*p[i].b;
ans-=2*p[i].b*bit.qry(p[i].a,p[i].a);
ans+=B.qry(p[i].a,p[i].a);
cnt.add(p[i].a,1);
bit.add(p[i].a,p[i].b);B.add(p[i].a,p[i].b*p[i].b);
}
cout<<ans<<endl;
return 0;
}
T3
谁懂从 15:00 调到 21:00 的破碎感
题意
给定大小为 \(n\) 的字符串序列 \(S\) 和大小为 \(m\) 的字符串序列 \(T\),其中 \(S\) 的第 \(i\) 个字符串为 \(S_i\),\(T\) 的第 \(j\) 个字符串为 \(T_j\)
定义一个字符串的权值 \(f(s)\) 为 \(s\) 中奇回文子串的个数,定义两个字符串的加法 \(s+t\) 为把两个字符串拼接起来得到的新字符串,求:
题解
容易想到答案的贡献来源于三部分:\(S_i\) 的所有奇回文子串,\(T_j\) 的所有奇回文子串,跨串的回文子串
前两个随便 Manacher 维护,最后一个比较头疼
考虑回文中心在 \(S_i\) 上,那么可以把所有的回文后缀拎出来,然后在 \(T_j\) 上跑匹配,怎么跑,字典树直接向下搜即可,直到没有转移边
代码
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define i2 __int128
#define pii pair<int,int>
#define fi first
#define se second
#define mkp make_pair
#define vi vector<int>
#define vp vector<pii>
#define pb push_back
using namespace std;
const int N=1e5+2,L=2e6+2,B=107;
const ll P=1e15+37;
int n,m,p[L];ll ans;string S[N],T[N];vp vec1[N],vec2[N];
i2 hsh[L],fac[L],inv[L];
struct Trie{
unordered_map<int,int> nxt[L];
int tot=1,q[L];ll sum[L];i2 H[L];
unordered_map<ll,int> mp;
inline void ins(string s,int len){
int now=1;
for(int i=1;i<=len;i++){
int x=s[i]-'a'+1;
if(!nxt[now].count(x)){
nxt[now][x]=++tot;
H[tot]=(H[now]+x*fac[i]%P)%P;
mp[(ll)(H[tot])]=tot;
}
now=nxt[now][x];sum[now]++;
}
return;
}
// inline void dfs(int u){
// if(!u)return;
// for(int i=1;i<=26;i++){
// if(nxt[u].count(i))sum[nxt[u][i]]+=sum[u];
// dfs(nxt[u][i]);
// }
// return;
// }
inline void bfs(){
int hd=1,tl=0;q[++tl]=1;
while(hd<=tl){
int u=q[hd++];
for(int i=1;i<=26;i++){
if(!nxt[u].count(i))continue;
sum[nxt[u][i]]+=sum[u];q[++tl]=nxt[u][i];
}
}
return;
}
inline void clr(){
for(int i=1;i<=tot;i++)sum[i]=H[i]=0,nxt[i].clear();
mp.clear();tot=1;
return;
}
}t1,t2;
inline void Manacher(string s,int len){
for(int i=1;i<=len;i++)p[i]=0;
int c=0,r=0,LEN=0;
for(int i=1;i<=len;i++){
LEN=(r>i?min(p[c*2-i],r-i):1);
while(i+LEN<=len&&i-LEN>=1&&s[i+LEN]==s[i-LEN])LEN++;
if(i+LEN>r)r=i+LEN,c=i;
p[i]=LEN;
}
return;
}
inline bool chk1(int l,int r,int len){
i2 _h=(hsh[l]-hsh[r+1]+P)%P*inv[len-r]%P;
// cerr<<"zyx "<<l<<' '<<r+1<<' '<<hsh[l]<<' '<<hsh[r+1]<<' '<<_h<<endl;
return t2.mp[_h];
}
inline void work1(int p){
int len=S[p].length()-1;
for(int i=1;i<=len+1;i++)hsh[i]=0;
for(int i=len;i>=1;i--)hsh[i]=(hsh[i+1]+(S[p][i]-'a'+1)*fac[len-i+1]%P)%P;
// for(int i=1;i<=len;i++)cerr<<hsh[i]<<" ";
// cerr<<endl;
for(pii o:vec1[p]){
int ed=o.fi-o.se;
int l=1,r=ed,pos=ed;
while(l<=r){
int mid=(l+r)>>1;
if(chk1(mid,ed,len))r=mid-1,pos=mid;
else l=mid+1;
}
if(pos>ed||pos==0)continue;
i2 _h=(hsh[pos]-hsh[ed+1]+P)%P*inv[len-ed]%P;
ans+=t2.sum[t2.mp[_h]];
}
return;
}
inline bool chk2(int l,int r,int len){
i2 _h=(hsh[r]-hsh[l-1]+P)%P*inv[l-1]%P;
return t1.mp[_h];
}
inline void work2(int p){
int len=T[p].length()-1;
for(int i=0;i<=len;i++)hsh[i]=0;
for(int i=1;i<=len;i++)hsh[i]=(hsh[i-1]+(T[p][i]-'a'+1)*fac[i]%P)%P;
for(pii o:vec2[p]){
int st=o.fi+o.se;
int l=st,r=len,pos=st;
while(l<=r){
int mid=(l+r)>>1;
if(chk2(st,mid,len))l=mid+1,pos=mid;
else r=mid-1;
}
i2 _h=(hsh[pos]-hsh[st-1]+P)%P*inv[st-1]%P;
ans+=t1.sum[t1.mp[_h]];
}
return;
}
inline void solve(){
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>S[i],S[i]=' '+S[i];
for(int i=1;i<=m;i++)cin>>T[i],T[i]=' '+T[i];
ll res=0ll;
for(int i=1;i<=n;i++){
int len=S[i].length()-1;Manacher(S[i],len);
for(int j=1;j<=len;j++)
if(j+p[j]-1==len)vec1[i].pb(mkp(j,p[j]));
for(int j=1;j<=len;j++)res+=p[j];
}
ans+=res*m*1ll;
res=0ll;
for(int i=1;i<=m;i++){
int len=T[i].length()-1;Manacher(T[i],len);
for(int j=1;j<=len;j++)
if(j==p[j])vec2[i].pb(mkp(j,p[j]));
for(int j=1;j<=len;j++)res+=p[j];
}
ans+=res*n*1ll;
for(int i=1;i<=n;i++){
int len=S[i].length()-1;string str=" ";
for(int j=len;j>=1;j--)str+=S[i][j];
t1.ins(str,len);
}
t1.bfs();
for(int i=1;i<=m;i++){
int len=T[i].length()-1;
t2.ins(T[i],len);
}
t2.bfs();
for(int i=1;i<=n;i++)work1(i);
for(int i=1;i<=m;i++)work2(i);
cout<<ans<<'\n';
return;
}
inline i2 qpow(i2 a,ll b){
i2 res=1;
while(b){
if(b&1)res=res*a%P;
a=a*a%P;b>>=1;
}
return res;
}
inline void init(){
fac[0]=1;
for(int i=1;i<L;i++)fac[i]=fac[i-1]*B%P;
inv[0]=1;inv[L-1]=qpow(fac[L-1],P-2);
for(int i=L-2;i>=1;i--)inv[i]=(i2)inv[i+1]*B%P;
return;
}
inline void clr(){
ans=0ll;
for(int i=1;i<=n;i++)vec1[i].clear(),vec1[i].shrink_to_fit();
for(int i=1;i<=m;i++)vec2[i].clear(),vec2[i].shrink_to_fit();
t1.clr(),t2.clr();
return;
}
signed main(){
freopen("str.in","r",stdin);
freopen("str.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
init();
int Case;cin>>Case;while(Case--)solve(),clr();
return 0;
}
T4
疑似简单题?然而只是云落比较菜?
题意

题解
二分图判无解是显然的
对于一个无向联通块,其内部可以黑白染色
再算上其它点,答案像极了一个 01 背包问题
问题是贡献如何计算
发现可以拆分鹅和鸭的贡献,鹅的贡献是 \({a_x}^2 + a_x a_y\),而鸭的贡献是 \({a_x}^2 - a_x a_y\)
剩下的就是代码实现咯,方案可以在背包过程中做
代码
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define vi vector<int>
#define pb push_back
using namespace std;
const int N=1e3+5;
int n,k,a[N],z[N][N],head[N],tot;
struct Edge{int to,nxt;}e[N*N];
int col[N],blk[N],W[N][2],V[N][2],tol,f[N][N],g[N][N];
vi vec[N];
inline void add(int u,int v){
e[++tot]={v,head[u]};head[u]=tot;
return;
}
inline bool dfs(int u){
blk[u]=tol;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(col[v]!=-1){
if(col[u]==col[v])return false;
continue;
}
col[v]=col[u]^1;
if(!dfs(v))return false;
}
return true;
}
inline bool check(){
for(int i=1;i<=n;i++){
if(col[i]==-1){
tol++;col[i]=0;
if(!dfs(i))return false;
}
}
return true;
}
signed main(){
freopen("ggd.in","r",stdin);
freopen("ggd.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>z[i][j];
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(z[i][j]&&z[j][i])add(i,j),add(j,i);
memset(col,-1,sizeof(col));
if(!check()){cout<<"NO\n";return 0;}
for(int i=1;i<=n;i++)vec[blk[i]].pb(i);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(!z[i][j])continue;
if(z[i][j]&&z[j][i]){
if(i>j)continue;
V[blk[i]][col[i]]+=a[i];
V[blk[i]][col[i]^1]+=a[j];
continue;
}
int o=a[i]*a[i]+a[j]*a[j];
if(blk[i]==blk[j]){
if(col[i]==col[j]){
V[blk[i]][col[i]]+=(o+2*a[i]*a[j]);
V[blk[i]][col[i]^1]+=(o-2*a[i]*a[j]);
}else{
V[blk[i]][0]+=o;
V[blk[i]][1]+=o;
}
}else{
int x=a[i]*a[i]+a[i]*a[j],y=a[i]*a[i]-a[i]*a[j];
V[blk[i]][col[i]]+=x;V[blk[i]][col[i]^1]+=y;
x=a[j]*a[j]+a[i]*a[j],y=a[j]*a[j]-a[i]*a[j];
V[blk[j]][col[j]]+=x;V[blk[j]][col[j]^1]+=y;
}
}
}
for(int i=1;i<=n;i++)W[blk[i]][col[i]^1]++;
memset(f,-0x3f,sizeof(f));
f[0][0]=0;
for(int i=1;i<=tol;i++){
for(int j=0;j<N;j++){
if(j>=W[i][0]&&f[i][j]<=f[i-1][j-W[i][0]]+V[i][0]){
f[i][j]=f[i-1][j-W[i][0]]+V[i][0],g[i][j]=0;
}
if(j>=W[i][1]&&f[i][j]<=f[i-1][j-W[i][1]]+V[i][1]){
f[i][j]=f[i-1][j-W[i][1]]+V[i][1],g[i][j]=1;
}
}
}
if(f[tol][k]<=-1e15){cout<<"NO\n";return 0;}
cout<<"YES\n";
for(int i=tol;i>=1;i--){
if(g[i][k]==1){
for(int x:vec[i])col[x]^=1;
k-=W[i][1];
}else k-=W[i][0];
}
for(int i=1;i<=n;i++)cout<<col[i]<<' ';
cout<<'\n';
return 0;
}
小结
T3 就纯一坨,T4 还不错捏
正文(加餐)
字符串选讲,难绷
关键词:字典树、模板、Manacher
其实并没有什么可以复盘的,都是板子
剩下的几个题当天还没有来得及补,挖个坑静等 AC 后叭!
(然而全是高效进阶或者板子题)
还剩了一个题目,继续挖坑待填
后记
世界孤立我任它奚落
完结撒花!

浙公网安备 33010602011771号