四连测Day2

少一句话,AK失败

不过跟熊god并列rank1也是一件幸事

T1 q次询问一个字符串两个后缀的最长前缀

10分钟打了一个后缀数组RMQ

然后过了样例 跟对拍拍过了1e7组数据

就没管它

考完试之后发现有$l==r$的情况。。。

于是爆炸 炸到30分

加一句话就100分 就整场比赛ak

当然 如果你不会后缀数组

我们可以hash

每次二分一个长度,O(1)判断哈希值是否相等

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const int maxn = 2e5 + 10;
char str[maxn];int n;
int st[maxn],top,lb[maxn],rb[maxn],r[maxn];
namespace Suffix_Array
{
    int rnk[maxn],tmp[maxn],sa[maxn],hei[maxn];
    int stb[maxn][20];
    int k;
    inline bool cmp(int i,int j)
    {
        if(rnk[i]!=rnk[j]) return rnk[i]<rnk[j];  
        else
        {  
            int ri=i+k<=n? rnk[i+k]:-1;  
            int rj=j+k<=n? rnk[j+k]:-1;  
            return ri<rj;  
        } 
    }
    void GetSA()
    {
        for(int i=0;i<=n;i++)
        {
            sa[i]=i;
            rnk[i]=i<n?str[i]:-1;
        }
        for(k=1;k<=n;k<<=1)
        {
            sort(sa,sa+n+1,cmp);
            tmp[sa[0]]=0;
            for(int i=1;i<=n;i++)tmp[sa[i]]=tmp[sa[i-1]]+(cmp(sa[i-1],sa[i])?1:0);
            for(int i=0;i<=n;i++)rnk[i]=tmp[i];
        }
    }
    void GetHeight()
    {
        for(int i=0;i<=n;i++)rnk[sa[i]]=i;
        int h=0;hei[0]=0;
        for(int i=0;i<n;i++)
        {
            if(h!=0)h--;
            if(!rnk[i])continue;
            int t=sa[rnk[i]-1];
            for(;i+h<n && t+h<n;h++) if(str[i+h]!=str[t+h]) break;
            hei[rnk[i]]=h;
        }
    }
    void initMin()
    {
        for(int i=1;i<=n;i++) stb[i][0] = hei[i];
        for(int j=1;(1<<j)<=n;j++)
            for(int i=1;i+(1<<j)-1<=n;i++)
                stb[i][j] = min(stb[i][j-1],stb[i+(1<<(j-1))][j-1]);
    }
    int RMQ(int L,int R)
    {
        int k=0;
        while((1<<(k+1)) <= R-L+1)k++;
        return min(stb[L][k],stb[R-(1<<k)+1][k]);
    }
    int LCP(int i,int j)
    {
        int L=rnk[i],R=rnk[j];
        if(L>R)swap(L,R);
        L++;return RMQ(L,R);
    }
}
using namespace Suffix_Array;
int main()
{
    freopen("lcp10.in","r",stdin);
    freopen("lcp10.out","w",stdout);
    scanf("%s",str);
    n = strlen(str);
    GetSA();GetHeight();initMin();
    int q = read();
    int ans = 0;
    while(q--)
    {
        int l = read(),r = read();
        if(l==r){cout<<n - l + 1<<endl;continue;}//一开始没写这句话 wa了 
        cout<<LCP(l - 1,r - 1)<<endl;
    }
}
View Code

T2 询问两个线段有没有交点

板子

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const int maxn = 1e5 + 10;
struct Vector
{
    double x,y;
    Vector operator + (const Vector &b)const
    {
        return (Vector){x + b.x,y + b.y};
    }
    Vector operator - (const Vector &b)const
    {
        return (Vector){x - b.x,y - b.y};
    }
    double operator * (const Vector &b)const
    {
        return x * b.x + y * b.y;
    }
    double len(){return (*this) * (*this);}
    double operator ^ (const Vector &b)const
    {
        return x * b.y - y * b.x;
    }
    void readvec()
    {
        x = read() * 1.0;
        y = read() * 1.0;
    }
};
#define Point Vector
struct Segment
{
    Point st,ed;
}ps[maxn << 1];
double dis(Point a,Point b){return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));}
double Area(Vector a,Vector b,Vector c){return (b - a) ^ (c - a);}
bool Intersec(Point a,Point b,Point c,Point d)
{
    if(max(a.x,b.x)<min(c.x,d.x))return false;
    if(max(a.y,b.y)<min(c.y,d.y))return false;    
    if(max(c.x,d.x)<min(a.x,b.x))return false;
    if(max(c.y,d.y)<min(a.y,b.y))return false;
    if(Area(c,b,a)*Area(b,d,a)<0)return false;
    if(Area(a,d,c)*Area(d,b,c)<0)return false;
    return true;
}
int main()
{
    freopen("intersect.in","r",stdin);
    freopen("intersect.out","w",stdout);
    int T = read();
    while(T--)
    {
        int n = read();
        ps[0].st.readvec();ps[0].ed.readvec();
        for(int i=1;i<=n;i++)
        {
            ps[i].st.readvec();
            ps[i].ed.readvec();
        }
        int flag = 0;
        for(int i=1;i<=n;i++)
        {
            if(Intersec(ps[0].st,ps[0].ed,ps[i].st,ps[i].ed))
            {
                flag = 1;break;
            }
        }
        if(flag)puts("YES");
        else puts("NO");
    }
}
View Code

T3 图论

你在点1处可以带一些油,每条道路有一个额外的权值c,表示当你剩余至少c的油的时候才能走这条路,走路需要费油

求1到n至少要带多少油

二分dij

结论...不是很会证明

二分一个油量,暴力从1到n沿当前能走的最短路走,判断能不能走到n就可以了

#include<bits/stdc++.h>
#define maxn 100005
#define LL long long
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
struct pa
 {
    int x;LL dis;
    bool operator <(const pa t1) const {return dis>t1.dis;}
};
bool vis[maxn];
priority_queue<pa> q;
int first[maxn],to[maxn << 1],nx[maxn << 1],v1[maxn << 1],v2[maxn << 1],cnt;
void add(int u,int v,LL c,LL w){to[++cnt] = v;nx[cnt] = first[u];first[u] = cnt;v1[cnt] = c;v2[cnt] = w;}
int n,m;
LL dis[maxn];
bool flag=0;
bool check(LL mid) 
{
    memset(vis,0,sizeof(vis));
    for(int i=2;i<=n;i++) dis[i]=1e9 + 777;dis[1]=0;
    q.push((pa){1,0});
    while(!q.empty()) 
    {
        pa now=q.top();q.pop();
        if(vis[now.x]) continue;
        vis[now.x]=1;
        for(int i=first[now.x];i;i=nx[i]) 
        {
            if(mid-now.dis<v2[i]) continue;
            if(dis[to[i]]>now.dis+v1[i])
            {
                dis[to[i]]=now.dis+v1[i];
                q.push((pa){to[i],dis[to[i]]});
            }
        }
    }
    if(vis[n]) flag=1;
    return vis[n];
}
int main() 
{
    freopen("spaceship.in","r",stdin);
    freopen("spaceship.out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        int u=read(),v=read(),c=read(),w=read();
        add(u,v,c,w);add(v,u,c,w);
    }
    LL l=0,r=2147483233333333LL;
    LL ans = 0;
    while(l<=r) 
    {
        LL mid=(l+r)>>1;
        if(check(mid)) {r=mid-1;ans = mid;}
        else l=mid+1;
    }
    if(flag==0) printf("-1
");
    else printf("%lld
",ans);
}
View Code
原文地址:https://www.cnblogs.com/Kong-Ruo/p/9442428.html