• 【hackerrank】Week of Code 30


    Candy Replenishing Robot

    Find the Minimum Number

    直接模拟

    Melodious password

    dfs输出方案

    Poles

    题意:有多个仓库,只能从后面的仓库运动前面的仓库,现在要把仓库合并成k个,移动一个仓库i到另个仓库j的代价是costi*(xi-xj),问最小代价。

    解一下就会发现是个斜率优化,做k次就可以了

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 100101
    #define LL long long
    #define rep(i,l,r) for(int i=l;i<=r;i++)
    #define dow(i,l,r) for(int i=r;i>=l;i--)
    using namespace std;
    
    LL sumd[maxn],sumw[maxn],f[2][maxn],d[maxn],w[maxn];
    int n,m,p[maxn];
    
    LL calc(int x,int y)
    {
        return f[y][x]-sumd[x];
    }
    int main()
    {
        scanf("%d %d",&n,&m);
        dow(i,1,n) scanf("%lld %lld",&d[i],&w[i]);
        rep(i,1,n) {
            sumw[i]=sumw[i-1]+w[i];
            sumd[i]=sumd[i-1]+d[i]*w[i];
        }
    //    rep(i,1,n) printf("%d %lld %lld %lld
    ",i,d[i],sumw[i],sumd[i]);printf("
    ");
        int now=0;
        rep(i,1,n) f[0][i]=-(sumw[i]-sumw[0])*d[i]+sumd[i]-sumd[0];
    //    rep(i,1,n) printf("%lld ",f[0][i]);printf("
    ");
        rep(i,2,m) {
            now=1-now;
            rep(j,1,n) f[now][j]=0;
            int head,tail;
            head=tail=1;
            p[1]=i-1;
            rep(j,i,n) {
        //        printf("%d %d
    ",head,tail);
        //        rep(k,head,tail) printf("%d ",p[k]);printf("
    ");
                while (head<tail && 
                    d[j]*(sumw[p[head+1]]-sumw[p[head]])<calc(p[head],1-now)-calc(p[head+1],1-now)) 
                        ++head;
                f[now][j]=(sumw[p[head]]-sumw[j])*d[j]+(sumd[j]-sumd[p[head]])+f[1-now][p[head]];
            //    printf("%lld %lld
    ",calc(p[tail],1-now),calc(j,1-now));
                while (head<tail && 
                    (calc(p[tail],1-now)-calc(j,1-now))*(sumw[p[tail]]-sumw[p[tail-1]])>(calc(p[tail-1],1-now)-calc(p[tail],1-now))*(sumw[j]-sumw[p[tail]]))
                        --tail;
                p[++tail]=j;
            }
        //    rep(j,1,n) printf("%lld ",f[now][j]);printf("
    ");
        }
        printf("%lld
    ",f[now][n]);
        return 0;
    } 
    View Code

    Range Modular Queries

    给一个数组,每次查询[l,r]中取模x为y的个数。

    我使用莫队直接写的,复杂度比较迷,其实可以预处理出模数为[1,10]的情况再莫队

    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define maxn 50000
    #define LL long long
    #define rep(i,l,r) for(int i=l;i<=r;i++)
    using namespace std;
    
    typedef struct {
        int l,r,k,id,x,y;
    }Que;
    Que que[maxn];
    int cmp(Que x,Que y)
    {
        if (x.k!=y.k) return x.k<y.k;
        return x.r<y.r;
    }
    int num[maxn],c[maxn],n,m,ans[maxn];
    
    int main()
    {
        scanf("%d %d",&n,&m);
        rep(i,0,n-1) scanf("%d",num+i);
        int len=sqrt(n);
        rep(i,0,m-1) {
            scanf("%d %d %d %d",&que[i].l,&que[i].r,&que[i].x,&que[i].y);
            que[i].id=i;
            que[i].k=que[i].l/len;
        }
        sort(que,que+m,cmp);
        int i=0;
        while (i<m) {
        //    printf("%d
    ",i);
            int k=que[i].k;
            memset(c,0,sizeof(c)); 
            rep(j,que[i].l,que[i].r) ++c[num[j]];
            int now;
            now=que[i].y;
            while (now<maxn) ans[que[i].id]+=c[now],now+=que[i].x;
        //    printf("!!
    ");
            ++i;
            while (que[i].k==k&&i<m) {
        //        printf("!!
    ");
                rep(j,que[i].l,que[i-1].l-1) c[num[j]]++;
                rep(j,que[i-1].l,que[i].l-1) c[num[j]]--;
                rep(j,que[i-1].r+1,que[i].r) c[num[j]]++;
                rep(j,que[i].r+1,que[i-1].r) c[num[j]]--;
                now=que[i].y;
                while (now<maxn) ans[que[i].id]+=c[now],now+=que[i].x;
                ++i;
            }
        //    printf("!!!
    ");
        }
        rep(i,0,m-1) printf("%d
    ",ans[i]);
        return 0; 
    } 
    View Code

    标解的方法显然更好,

    分两部分处理,1-k和k到n(k=sqrt(n));

    对于第一部分,建立一个pos[i][j]的vector表示模数为i,结果为j的数的下标,每次查询就直接二分找出下标,相减就是个数。

    对于第二部分,建立一个poss[i]的vector表示数为i的下标,对于每次询问从x开始,每次查询l,r区间有多少个这个数,一样是二分查找下标相减

    A Graph Problem

    题意:给一个图,让你选出其中一些点,使得这些点中边组成的三角形/点的个数最大。

    求比值最大显然是01分数规划,化简一下就是y-g*x=0,这是一个最大权闭合图,用网络流建图解决。记住收益=正的收益-最小割(最大流),收益>0就是存在方案。不过最后要输出方案我gg了,一个是精度,另一个是最后要用l重新跑一遍,然后找出和s不在一个集合的点,就是从s开始dfs找不到的点,

    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define LL long long
    #define maxn 100000
    #define maxm 100000
    #define rep(i,l,r) for(int i=l;i<=r;i++)
    #define dow(i,l,r) for(int i=r;i>=l;i--)
    #define repedge(i,x) for(int i=cur[x];i>=0;i=e[i].next)
    #define repedge2(i,x) for(int i=cur[x];i>=0;i=e[i].next)
    #define inf 10000
    using namespace std;
    
    typedef struct {
        int toward,next;
        double cap;
    } Edge;
    
    Edge e[maxm];
    int d[maxn],chose[maxn],gap[maxn],fi[maxn],cur[maxn],n,m,tot1,total,tar[maxn][3],ap[100][100],s,t;
    double esp=0.000000001;
    
    void add(int j,int k,double l)
    {
        e[total].toward=k;
        e[total].next=fi[j];
        fi[j]=total;
        e[total].cap=l;
        ++total; 
    }
    
    void addedge(int j,int k,double l)
    {
        add(j,k,l);
        add(k,j,0);
    }
    
    double sap(int x,double flow)
    {
    //    printf("%d %lf
    ",x,flow);
        if (x==t) return flow;
        double now=0;
        repedge(i,x) {
            int too=e[i].toward;
            if (d[x]==d[too]+1 && e[i].cap>0) {
                double more=sap(too,min(e[i].cap,flow-now));
                e[i].cap-=more;
                e[i^1].cap+=more;
                cur[x]=i;
                if (flow==(now+=more)) return flow;
            }
        }    
        if (!(--gap[d[x]])) d[s]=t;
        gap[++d[x]]++;
        cur[x]=fi[x];
        return now;
    } 
    
    double maxflow()
    {
        rep(i,1,t) d[i]=0,gap[i]=0,cur[i]=fi[i];
        gap[0]=t;
        double sum=0;
        while (d[s]<t) sum+=sap(s,inf);
        return sum;
    } 
     
    void dfs(int x)
    {
    //    printf("%d
    ",x);
        chose[x]=1;
        repedge2(i,x) {
            int too=e[i].toward;
    //        printf("	%d %lf
    ",too,e[i].cap);
            if (e[i].cap>esp && !chose[too]) dfs(too);
        }
    } 
    int main()
    {
        scanf("%d",&n);
        rep(i,1,n) 
            rep(j,1,n) scanf("%d",&ap[i][j]);
        tot1=0;
        rep(i,1,n)
            rep(j,i+1,n)
                rep(k,j+1,n) 
                    if (ap[i][j] && ap[i][k] && ap[j][k]) {
                        ++tot1;
                        tar[tot1][0]=i;
                        tar[tot1][1]=j;
                        tar[tot1][2]=k;
                    }
        s=n+tot1+1;t=n+tot1+2;
        double l=0,r=1000;
        while (r-l>=esp) {
            double mid=(l+r)/2.0;
        //    printf("%lf
    ",mid);
            total=0;
            rep(i,1,t) fi[i]=-1;
            rep(i,1,tot1) 
                rep(j,0,2) addedge(tar[i][j],i+n,inf);
            rep(i,1,n) addedge(s,i,mid);
            rep(i,1,tot1) addedge(i+n,t,1);
            if (tot1-maxflow()>0) l=mid;
            else r=mid;
        }
    //    printf("%lf %lf %lf
    ",l,r,(l+r)/2);
        total=0;
        rep(i,1,t) fi[i]=-1;
        rep(i,1,tot1) 
            rep(j,0,2) addedge(tar[i][j],i+n,inf);
        rep(i,1,n) addedge(s,i,l);
        rep(i,1,tot1) addedge(i+n,t,1);
        maxflow();
        memset(chose,0,sizeof(chose));
        dfs(s);
        int tot2=0;
        rep(i,1,n) if (!chose[i]) ++tot2;
        printf("%d
    ",tot2);
        rep(i,1,n) if (!chose[i]) printf("%d ",i);
        printf("
    ");
        return 0;
    } 
    View Code

    Substring Queries

    给多个字符串,求出其中某两个字符串的lcp。

    建立一个广义后缀数组。然后记录每个字符串的后缀在sa[]中的位置,对于一个询问,s1,s2,取出s1的每一个后缀和s2的每一个后缀算一个lcp,可以发现只会和s2中最接近这个后缀的两个后缀有关系,也就是每次都是单调的,一次询问就是s1+s2的后悔次数,然后做两个小优化,一个是把询问一样的一起处理,一个是每次s1选取那个短一点的,最后摊下来是一个比较好看的复杂度。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #define maxn 210000
    #define maxm 210000
    #define rep(i,l,r) for(int i=l;i<=r;i++) 
    #define dow(i,l,r) for(int i=r;i>=l;i--)
    using namespace std;
    
    vector<int> vec[maxn];
    int len,n,f[20][maxn],tot,sa[maxn],ran[maxn],h[maxn],num[maxn],d[maxn],ans[maxn],x[maxn],y[maxn],c[maxn],m,size[maxn],col[maxn];
    char s[maxn],st[maxn];
    
    typedef struct {
        int l,r,id;
    }Que;
    Que que[maxn];
    int cmp(Que a,Que b)
    {
        if (a.r!=b.r) return a.r<b.r;
        return a.l<b.l;
    }
    
    void makesa()
    {
        for(int p=1;p<len;p*=2) {
        //    printf("%d
    ",p);
            rep(i,1,p) y[i]=len-p+i;
            int j=p;
            rep(i,1,len) 
                if (sa[i]>p) y[++j]=sa[i]-p;
            rep(i,1,len) x[i]=ran[y[i]];
            memset(c,0,sizeof(c));
            rep(i,1,len) c[x[i]]++;
            rep(i,1,tot) c[i]+=c[i-1];
            dow(i,1,len) sa[c[x[i]]--]=y[i];
            x[sa[tot=1]]=1;
            rep(i,2,len) {
                tot+=(ran[sa[i]]!=ran[sa[i-1]] || ran[sa[i]+p]!=ran[sa[i-1]+p]);
                x[sa[i]]=tot;
            }
            rep(i,1,len) ran[i]=x[i];
    //        rep(i,1,len) printf("%s
    ",&s[sa[i]]);
            if (tot==len) break;
        }
        rep(i,1,len) sa[ran[i]]=i;
    }
    
    void makeheight()
    {
        h[1]=0;
        int last=0;
        rep(i,1,len) {
            last=max(last-1,0);
            if (ran[i]==1) continue;
            int j=sa[ran[i]-1];
            while (s[i+last]==s[j+last]) ++last;
            h[ran[i]]=last;
        }
    }
    
    void into()
    {
        scanf("%d %d",&n,&m);
        len=0;
        rep(i,1,n) {
            scanf("%s",st);
            size[i]=strlen(st);
            s[++len]='#';
            rep(j,0,size[i]-1) {
                s[++len]=st[j];
                d[len]=size[i]-j;
                col[len]=i;
            }
        }
        s[++len]='$';
        memset(c,0,sizeof(c));
        rep(i,1,len) c[x[i]=s[i]]++;
        rep(i,1,128) c[i]+=c[i-1];
        dow(i,1,len) sa[c[x[i]]--]=i;
        ran[sa[tot=1]]=1;
        rep(i,2,len) 
            ran[sa[i]]=(tot+=(x[sa[i]]!=x[sa[i-1]]));
    //    printf("%d
    ",tot);
    //    rep(i,1,len) printf("%s
    ",&s[sa[i]]);
        makesa();
    //    printf("!!!
    "); 
        makeheight();
    //    printf("!!!
    "); 
    //    rep(i,1,len) printf("%3c",s[i]);printf("
    ");
    //    rep(i,1,len) printf("%3d",sa[i]);printf("
    ");
    //    rep(i,1,len) printf("%3d",rank[i]);printf("
    ");
    //    rep(i,1,len) printf("%3d",h[i]);printf("
    ");
    //    rep(i,1,len) printf("%3d",col[i]);printf("
    ");
    //    rep(i,1,len) printf("%s
    ",&s[sa[i]]);
        rep(i,2,len) h[i]=min(h[i],d[sa[i]]);
        rep(i,1,len) {
            int j=col[sa[i]];
        //    printf("%d %d
    ",j,i);
            if (j) vec[j].push_back(i);
        }
    //    rep(i,1,n) {
    //        printf("%d:%d",i,vec[i].size()); 
    //        rep(j,0,vec[i].size()-1) printf("%3d",vec[i][j]);
    //        printf("
    ");
    //    } 
        rep(i,1,len) f[0][i]=h[i];
        rep(i,1,19)
            rep(j,1,len-(1<<i)+1) 
                f[i][j]=min(f[i-1][j],f[i-1][j+(1<<(i-1))]);
    //    rep(i,0,16) 
    //        rep(j,1,len-(1<<i)+1) 
    //            printf("%d %d %d %d
    ",i,j,j-1+(1<<i),f[i][j]);
    //    printf("!!
    ");
        rep(i,0,len) num[i]=(int)floor(log(i)/log(2));
    }
    
    int calc(int l,int r)
    {
    //    printf("%d %d
    ",l,r);
        if (l>r) swap(l,r);
        l++;
        int i=num[r-l+1];
        return min(f[i][l],f[i][r+1-(1<<i)]);
    }
    
    void ask()
    {
        rep(i,0,m-1) {
            scanf("%d %d",&que[i].l,&que[i].r);
            ++que[i].r;
            ++que[i].l;
            if (size[que[i].l]<size[que[i].r]) swap(que[i].l,que[i].r);
            que[i].id=i;
        }
        sort(que,que+m,cmp);
    //    printf("!!
    ");
    //    rep(i,0,m-1) printf("%d %d %d
    ",que[i].l,que[i].r,que[i].id);
        rep(i,0,m-1) {
            if (i && que[i].l==que[i-1].l && que[i].r==que[i-1].r) ans[que[i].id]=ans[que[i-1].id];
            else {
                int now=0,x=que[i].r,y=que[i].l,last=0;
                rep(j,0,size[x]-1) {
                    while (now+2<size[y] && vec[y][now+1]<vec[x][j]) ++now;
                    last=max(last,calc(vec[x][j],vec[y][now]));
                    if (now<size[y]) last=max(last,calc(vec[x][j],vec[y][now+1]));
                }
                ans[que[i].id]=last;
            }
        }
        rep(i,0,m-1) printf("%d
    ",ans[i]);
    }
    int main()
    {
        into();
        ask();
        return 0;
    }
    View Code

    说到底还是自己太弱,很怠惰,本来倒数第二题思路是对的一直不敢写,想想这星期除了cf就只有这一点点练习,真是的!

  • 相关阅读:
    作业十三
    作业十二
    第十一次作业
    编译原理第十次作业
    P3388 【模板】割点(割顶) 题解 (Tarjan)
    BuaacodingT141 microhhh的回城 题解(模拟)
    P2055 [ZJOI2009]假期的宿舍 题解(二分图)
    P2764 最小路径覆盖问题 题解(二分图)
    2019.2-2019.3 TO-DO LIST
    P3369 【模板】普通平衡树 题解(Splay/FHQ)
  • 原文地址:https://www.cnblogs.com/Macaulish/p/6613651.html
Copyright © 2020-2023  润新知