题解- sxyz 5.20 膜你赛
吐槽时间:
- 道题目要开 ,然后我只开了一题(白丢 分)
- 最后只有 ,竟然还拿了
- 又被 以 分吊锤了
-
题目意思:给你一个长为 的串(仅仅包含 三个字母)。问最大长度的子串使得这个区间内 数量相同。
-
SOL: 送分题,对于每个字母哈希使得 ,具体的让 。然后在区间内最长和为 段即可(开个 就够了)。时间复杂度
-
CODE:
#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
#define int long long
#pragma GCC optimize(3,"Ofast","inline")
#pragma GCC target("avx")
#define pb push_back
using namespace std;
inline int read()
{
int sum=0,ff=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum*ff;
}
const int N=2e5+5;
const int AD=2e5;
const int DE=2e5+1;
int n,m,a[N],ans;
char ch[N];
map<int,int> yzc;
inline int max(int i,int j)
{
if(i>j) return i;
return j;
}
signed main()
{
n=read();
scanf("%s",ch+1);
for ( register int i=1;i<=n;++i )
{
if(ch[i]=='J') m++;
if(ch[i]=='O') m+=AD;
if(ch[i]=='I') m-=DE;
if(!m)
{
ans=max(ans,i);
continue;
}
if(yzc[m]) ans=max(ans,i-yzc[m]);
if(!yzc[m]) yzc[m]=i;
}
printf("%lld\n",ans);
return 0;
}
-
题目意思:传送门
-
SOL: 一开始我只会做暴力分(真的傻)。还没有用链表,本来换可以白骗 。其实正解是基于暴力的优化。暴力是这样的我们枚举每个人每次做一遍最大生成树取出里面的点赋值即可。这样的复杂度是 的。我们考虑枚举边然后二分是哪个人删的(怎么判断呢,我们发现第一个出现这条边的两个断点还没连通的那个人被删)。对于维护只有开 个并查集即可。时间复杂度
-
CODE:
#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
#define pb push_back
using namespace std;
inline int read()
{
int sum=0,ff=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum*ff;
}
const int N=1e4+5;
const int M=1e3+5;
const int E=3e5+5;
int n,m,K,fa[M][N],ans[E];
struct Node
{
int x,y,w,id;
inline bool friend operator < (const Node&a,const Node&b)
{
return a.w>b.w;
}
};
Node a[E];
inline int find(int x,int k)
{
if(fa[x][k]==x) return x;
return fa[x][k]=find(fa[x][k],k);
}
int main()
{
n=read();
m=read();
K=read();
for ( int i=1;i<=m;i++ )
{
int x,y,z;
x=read(),y=read(),z=read();
a[i]=(Node){x,y,z,i};
}
sort(a+1,a+m+1);
for ( int i=1;i<=n;i++ )
for ( int j=1;j<=K;j++ ) fa[i][j]=i;
for ( int i=1;i<=m;i++ )
{
int x=a[i].x,y=a[i].y;
int l=1,r=K,ALB=0;
while(l<=r)
{
int mid=(l+r)/2;
if(find(x,mid)!=find(y,mid)) ALB=mid,r=mid-1;
else l=mid+1;
}
if(!ALB) continue;
ans[a[i].id]=ALB;
fa[find(x,ALB)][ALB]=find(y,ALB);
}
for ( int i=1;i<=m;i++ ) printf("%d\n",ans[i]);
return 0;
}
- 题目意思:传送门
- SOL: 神仙思维题。我们考虑这段序列:
粗的是 ,否则为
我们考虑每次翻转相当于从 。推而广之翻转 相当于 。而对于那些走回头路的(就是翻转两次相当于没翻转)贡献是没有的但是代价要算的。现在我们的目标是都朝上,我们考虑如何翻转(莫过于 种情况)。看下图:
这里的重叠部分就是走回头路的过程,所以对上述三种情况取
即可。
- CODE
#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
#define pb push_back
#define int long long
using namespace std;
inline int read()
{
int sum=0,ff=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum*ff;
}
const int base=197;
const int N=5e5+5;
int n,m,cnt,dis[4][N],vis[N],ans;
int a,b,c,d,E,head[N];
struct Node
{
int nex,to,w;
};
Node e[N<<1];
inline void jia(int u,int v,int w)
{
e[++cnt].nex=head[u];
head[u]=cnt;
e[cnt].to=v;
e[cnt].w=w;
}
inline void spfa(int op,int s)
{
for ( int i=0;i<=a+b+c+d+E+1;i++ ) dis[op][i]=1e14,vis[i]=0;
memset(vis,0,sizeof(vis));
queue<int> q;
q.push(s);
dis[op][s]=0,vis[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for ( int i=head[u];i;i=e[i].nex )
{
int v=e[i].to;
if(dis[op][v]>dis[op][u]+e[i].w)
{
dis[op][v]=dis[op][u]+e[i].w;
if(!vis[v])
vis[v]=1,q.push(v);
}
}
}
}
signed main()
{
a=read();
b=read();
c=read();
d=read();
E=read();
n=read();
for ( int i=1;i<=n;i++ )
{
int l,r;
l=read(),r=read();
jia(l,r+1,(r-l+1));
jia(r+1,l,(r-l+1));
}
spfa(0,a+1);
spfa(1,a+b+1);
spfa(2,a+b+c+1);
ans=1e14;
ans=min(ans,dis[0][a+b+1]+dis[2][a+b+c+d+1]);
ans=min(ans,dis[0][a+b+c+1]+dis[1][a+b+c+d+1]);
ans=min(ans,dis[0][a+b+c+d+1]+dis[1][a+b+c+1]);
if(ans==1e14) ans=-1;
printf("%lld\n",ans);
return 0;
}