【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\n",i,d[i],sumw[i],sumd[i]);printf("\n");
    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("\n");
    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\n",head,tail);
    //        rep(k,head,tail) printf("%d ",p[k]);printf("\n");
            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\n",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("\n");
    }
    printf("%lld\n",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\n",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("!!\n");
        ++i;
        while (que[i].k==k&&i<m) {
    //        printf("!!\n");
            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("!!!\n");
    }
    rep(i,0,m-1) printf("%d\n",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\n",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\n",x);
    chose[x]=1;
    repedge2(i,x) {
        int too=e[i].toward;
//        printf("\t%d %lf\n",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\n",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\n",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\n",tot2);
    rep(i,1,n) if (!chose[i]) printf("%d ",i);
    printf("\n");
    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\n",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\n",&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\n",tot);
//    rep(i,1,len) printf("%s\n",&s[sa[i]]);
    makesa();
//    printf("!!!\n"); 
    makeheight();
//    printf("!!!\n"); 
//    rep(i,1,len) printf("%3c",s[i]);printf("\n");
//    rep(i,1,len) printf("%3d",sa[i]);printf("\n");
//    rep(i,1,len) printf("%3d",rank[i]);printf("\n");
//    rep(i,1,len) printf("%3d",h[i]);printf("\n");
//    rep(i,1,len) printf("%3d",col[i]);printf("\n");
//    rep(i,1,len) printf("%s\n",&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\n",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("\n");
//    } 
    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\n",i,j,j-1+(1<<i),f[i][j]);
//    printf("!!\n");
    rep(i,0,len) num[i]=(int)floor(log(i)/log(2));
}

int calc(int l,int r)
{
//    printf("%d %d\n",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("!!\n");
//    rep(i,0,m-1) printf("%d %d %d\n",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\n",ans[i]);
}
int main()
{
    into();
    ask();
    return 0;
}
View Code

 

 

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

posted @ 2017-03-24 21:59  Macaulish  阅读(302)  评论(0编辑  收藏  举报