zoukankan      html  css  js  c++  java
  • 【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就只有这一点点练习,真是的!

  • 相关阅读:
    Notes about "Exploring Expect"
    Reuse Sonar Checkstyle Violation Report for Custom Data Analysis
    Eclipse带参数调试的方法
    MIT Scheme Development on Ubuntu
    Manage Historical Snapshots in Sonarqube
    U盘自动弹出脚本
    hg的常用配置
    Java程序员的推荐阅读书籍
    使用shared memory 计算矩阵乘法 (其实并没有加速多少)
    CUDA 笔记
  • 原文地址:https://www.cnblogs.com/Macaulish/p/6613651.html
Copyright © 2011-2022 走看看