zoukankan      html  css  js  c++  java
  • 四连测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
  • 相关阅读:
    《数据结构第一章复习》
    《图的基本操作》
    《矩阵的一些基本操作》
    <矩阵的基本操作:矩阵相加,矩阵相乘,矩阵转置>
    《两个二维数组(矩阵)相乘》
    C#隐藏与显示系统任务栏和开始菜单栏按钮
    C#通过窗体属性缩小一定尺寸时,无法再缩小窗体尺寸问题
    C#一个窗体调用另一个窗体的方法
    C#异步线程
    C#中MessageBox.Show问题(让提示窗口不显示在任务栏中)
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/9442428.html
Copyright © 2011-2022 走看看