zoukankan      html  css  js  c++  java
  • [2019杭电多校第五场]

    1004传送门


    题意:求(sum_{i=1}^n) (mid)a[i] * x+b[i](mid)=C(其中1<=ai<=1000,-1000<=b[i]<=1000)的所有解,如果解有无穷个则输出-1
    题解:由于a[i]>=1,所以(mid)a[i] * x+b[i](mid)的值在x=-b[i]/a[i]左边时-a[i] * x-b[i],在x=-b[i]/a[i]右边时a[i] * x+b[i],所以可以按照零点位置将n个绝对值式子排序,将数轴以这些点为界限分成若干区间,从左到右按顺序处理即可

    #include<bits/stdc++.h>
    using namespace std;
    //#define debug(x) cout<<#x<<" is "<<x<<endl;
    typedef long long ll;
    const int maxn=1e5+5;
    ll ans1[maxn],ans2[maxn];
    struct pot{
        ll a;
        ll b;
    }p[maxn];
    bool cmp(struct pot aa,struct pot bb){
        return bb.a*aa.b>aa.a*bb.b;
    }
    ll gcd(ll x,ll y){
        if(y==0)return x;
        return gcd(y,x%y);
    }
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            ll n,c;
            scanf("%lld%lld",&n,&c);
            for(int i=1;i<=n;i++)scanf("%lld%lld",&p[i].a,&p[i].b);
            sort(p+1,p+1+n,cmp);
            ll s1=0;
            ll s2=0;
            int f=1;
            int tot=0;
            for(int i=1;i<=n;i++){s1-=p[i].a;s2-=p[i].b;}
            if(s1==0&&s2==c){f=0;printf("-1
    ");continue;}
            if((s1>0&&(c-s2)*(p[1].a)<=(-s1*p[1].b))||(s1<0&&(c-s2)*(p[1].a)>=(-s1*p[1].b))){
                if(c-s2==0){s1=1;}
                ans1[++tot]=s1;
                ans2[tot]=c-s2;
            }
            int j;
            for(int i=1;i<=n;i=j){
                j=i;
                while(j<=n&&p[j].a*p[i].b==p[j].b*p[i].a){s1+=2*p[j].a;s2+=2*p[j].b;j++;}
                if(s1==0&&s2==c){f=0;break;}
                if(((j==n+1)||((s1>0&&(c-s2)*(p[j].a)<=(-s1*p[j].b))||(s1<0&&(c-s2)*(p[j].a)>=(-s1*p[j].b))))&&(((s1>0&&(c-s2)*(p[i].a)>=(-s1*p[i].b))||(s1<0&&(c-s2)*(p[i].a)<=(-s1*p[i].b))))){
                    if(tot){
                        if(ans2[tot]*s1==ans1[tot]*(c-s2))continue;
                    }
                    if(c-s2==0){s1=1;}
                    ans1[++tot]=s1;
                    ans2[tot]=c-s2;
                }
            }
            if(f==0)printf("-1
    ");
            else{
                printf("%d",tot);
                for(int i=1;i<=tot;i++){
                    if(ans2[i]==0){printf(" 0/1");}
                    else{
                        int xx=gcd(ans1[i],ans2[i]);
                        int sgn=1;
                        if(ans2[i]*ans1[i]<0)sgn=-1;
                        printf(" %lld/%lld",sgn*abs(ans2[i]/xx),abs(ans1[i]/xx));
                    }
                }
                printf("
    ");
            }
        }
        return 0;
    }
    

    1005传送门


    题意:求出一个1到n的n个数字的一个排列并且这个排列p[i+1]-p[i]的字典序第k小
    题解:使用如下dfs直接搜索p[i+1]-p[i]的值可以比较容易地找到字典序第k小的方案,重点在于复杂度的分析(代码下方附上我的分析..如有错误望指正(>_<)..)

    #include<bits/stdc++.h>
    using namespace std;
    //#define debug(x) cout<<#x<<" is "<<x<<endl;
    typedef long long ll;
    const int maxn=105;
    bool vis[maxn*4];
    int n,k,a[maxn];
    int res;
    bool dfs(int sum,int pos,int maxx,int minn){
        if(pos==n-1){
            res--;
            if(!res){
                int ss=n-maxx;
                a[0]=0;
                for(int i=1;i<=n;i++){
                    printf("%d",ss+a[i-1]);
                    ss+=a[i-1];
                    char cc=(i==n)?'
    ':' ';
                    printf("%c",cc);
                }
                return 1;
            }
            return 0;
        }
        for(int i=1-n-sum+max(0,maxx);i<=n-sum-1+min(minn,0);i++){
            if(vis[i+sum+200])continue;
            vis[i+sum+200]=1;
            a[pos+1]=i;
            if(dfs(sum+i,pos+1,max(maxx,i+sum),min(minn,i+sum))){
                vis[i+sum+200]=0;
                return 1;
            }
            vis[i+sum+200]=0;
        }
        return 0;
    }
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&k);
            vis[200]=1;
            res=k;
            dfs(0,0,0,0);
        }
        return 0;
    }
    

    复杂度分析:由界定条件 for(int i=1-n-sum+max(0,maxx);i<=n-sum-1+min(minn,0);i++)保证这个dfs每次搜索的是一个p[i+1]-p[i]的排列,也就是不会出现搜索到无用结点的情况,每个结点最后都通向至少一个可行解,又由于只会搜索前k小的字典序,所以只有k个叶子结点,而每个被搜索到的结点都至少会被一个叶子结点经过,并且每个叶子结点到根的距离是n,所以至多会有kn个结点,而每个结点的复杂度为n,所以总的时间复杂度为O(kn*n)

    1006传送门



    题意:求以(sum_{i=1}^(n-1))F(i),其中F(i)表示以s[i]开头的字符串与s[0]开头的字符串的相同前缀的长度
    题解:exkmp裸题

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    char sa[1100000],sb[1100000];
    int lena,lenb;
    typedef long long ll;
    ll p[1100000],ex[1100000];
    //p数组是用来让B串自己匹配自己的
    void exkmp()
    {
        p[1]=lenb;
        int x=1;
        while(sb[x]==sb[x+1]&&x+1<=lenb) x++;//因为我们p[1]是具有一定性,所以我们不能直接用,所以要先暴力求出p[2]
        p[2]=x-1;
        int k=2;
        for(int i=3;i<=lenb;i++)
        {
            int pp=k+p[k]-1,L=p[i-k+1];//pp实际上是p
            if(i+L<pp+1) p[i]=L;//i-k+L<pp-k+1化简后i+L<pp
            else
            {
                int j=pp-i+1;
                if(j<0) j=0;
                while(sb[j+1]==sb[i+j]&&i+j<=lenb) j++;
                p[i]=j;
                k=i;
            }
        }
        x=1;
        while(sa[x]==sb[x]&&x<=lenb) x++;//ex[1]并不具有一定性,所以我们暴力求出ex[1]
        ex[1]=x-1;
        k=1;
        for(int i=2;i<=lena;i++)
        {
            int pp=k+ex[k]-1,L=p[i-k+1];
            if(i+L<pp+1) ex[i]=L;
            else
            {
                int j=pp-i+1;
                if(j<0) j=0;
                while(sb[j+1]==sa[i+j]&&i+j<=lena&&j<=lenb) j++;
                ex[i]=j;
                k=i;
            }
        }
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
            scanf("%s",sb+1);
            lenb=strlen(sb+1);
            lena=lenb-1;
            for(int i=1;i<lenb;i++){
                sa[i]=sb[i+1];
            }
            exkmp();
            ll ans=lena;
            for(int i=1;i<=lena;i++){ans+=ex[i];if(ex[i]+i>lena)ans--;}// printf("%d ",ex[i]);
            printf("%lld
    ",ans);
        }
        return 0;
    }
    

    1007传送门


    题意:求题设要求的某种排列的方案数
    题解:打表

    #include<bits/stdc++.h>
    using namespace std;
    #define debug(x) cout<<#x<<" is "<<x<<endl;
    typedef long long ll;
    const int maxn=1e5+5;
    const ll mod=998244353;
    int a[maxn];
    ll ans[maxn];
    int main(){
        ans[0]=ans[1]=ans[2]=1;
        ans[3]=2;
        for(int i=4;i<maxn;i++)ans[i]=(ans[i-1]+ans[i-3])%mod;
        int t;
        scanf("%d",&t);
        while(t--){
            ll n,x,y;
            scanf("%lld%lld%lld",&n,&x,&y);
            ll xx=max(x,y);
            ll yy=min(x,y);
            x=yy;
            y=xx;
            if(y!=n)y--;
            if(x!=1)x++;
            int xxx=y-x;
            if(xxx<0)printf("0
    ");
            else printf("%lld
    ",ans[xxx]);
        }
        return 0;
    }
    

    打表代码

    #include<bits/stdc++.h>
    using namespace std;
    #define debug(x) cout<<#x<<" is "<<x<<endl;
    typedef long long ll;
    const int maxn=1e5+5;
    const ll mod=998244353;
    int a[maxn];
    int main(){
        while(1){
            int n,x,y;
            scanf("%d%d%d",&n,&x,&y);
            int tot=0;
            a[0]=x;
            a[n-1]=y;
            int ac=0;
            for(int i=1;i<=n;i++){
                if(i==x||i==y)continue;
                a[++tot]=i;
            }
            do{
                int f=1;
                for(int i=1;i<=n-1;i++){
                    if(abs(a[i]-a[i-1])>2){f=0;break;}
                }
                if(f){
                    ac++;
                }
            }while(next_permutation(a+1,a+1+tot));
            printf("%d
    ",ac);
        }
        return 0;
    }
    
  • 相关阅读:
    优先级队列
    内存拷贝
    快速排序
    ubuntu上编译Thrift
    Hadoop 学习总结之一:HDFS简介(zz写的很不错)
    hbase 详细解析(转载)
    HBase技术介绍简介 NOSQL数据库 入门(转载)
    SQL到NOSQL的思维转变
    Hadoop分布式文件系统:架构和设计(zz)
    zz我对技术方向的一些反思
  • 原文地址:https://www.cnblogs.com/MekakuCityActor/p/11317345.html
Copyright © 2011-2022 走看看