zoukankan      html  css  js  c++  java
  • 2017-3-23校内训练

    学长日常出丧题虐人 100+90+64=254/300

    T1.数据结构

    题目大意:给定n个数,每次给出x和y,询问一个区间内多少数模x等y。(n,询问次数,数字大小<=40000)

    思路:用差分或者说是前缀和的思想,离线处理每个询问,我们从左到右把数字加入某种能查询模x等y的数据结构中,碰到询问区间左端点时让该询问的答案减去当前数据结构中模x等y的个数,碰到右端点时再加上这个个数。那么如何维护这个数据结构呢?可以分类讨论,对于x<=200,我们用数组f1[i][j]存下模i等j的值的个数,每次O(200)暴力修改,O(1)查询,对于x>200,我们用f2[i]存下值为i的个数,每次O(1)修改,查询的时候我们枚举y,x+y,2x+y……复杂度最大为O(40000/200=200)。总复杂度O(200(n+q))。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 40000
    #define K 200
    struct query{int p,x,y,i,f;}p[MN*2+5];
    bool cmp(query a,query b){return a.p==b.p?a.f<b.f:a.p<b.p;}
    int a[MN+5],ans[MN+5],f[K+5][K+5],ff[MN+5];
    int cal(int x,int y)
    {
        if(x<=K)return f[x][y];
        int i,r=0;
        for(i=y;i<=MN;i+=x)r+=ff[i];
        return r;
    }
    int main()
    {
        freopen("datastructure.in","r",stdin);
        freopen("datastructure.out","w",stdout);
        int n,q,i,j,k,l,r,x,y;
        n=read();q=read();
        for(i=1;i<=n;++i)a[i]=read();
        for(i=0;i<q;++i)
        {
            l=read();r=read();x=read();y=read();
            p[i<<1]=(query){l,x,y,i,-1};
            p[i<<1|1]=(query){r,x,y,i,1};
        }
        sort(p,p+(q<<1),cmp);
        for(i=1,j=0;i<=n;++i)
        {
            for(;p[j].p==i&&p[j].f<0;++j)ans[p[j].i]-=cal(p[j].x,p[j].y);
            for(k=1;k<=K;++k)++f[k][a[i]%k];++ff[a[i]];
            for(;p[j].p==i;++j)ans[p[j].i]+=cal(p[j].x,p[j].y);
        }
        for(i=0;i<q;++i)printf("%d
    ",ans[i]);
        fclose(stdin);fclose(stdout);return 0;
    }

    T2.刷水

    题目大意:n道题,第i道在xi时出现,每道题开始难度为0,之后每秒增加wi,总共可以做k次题,问做完所有题的最小难度和。(n,k<=5000)

    思路:容易想到用f[i][j]表示做i次做完前j道的最小难度和,则f[i][j]=min(f[i-1][p]+Σwl*(xj-xl)) (p<l<j),随便斜率优化就可以了,复杂度O(nk),我突然脑抽没想出来,打了决策单调性,多个log,本机测极限数据2.3s,时限3s,就放心交了,结果因为迷之原因被卡常了两个点(评测机配置与本机相同),拿到包自己测了下A了,玄学。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ll long long
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 5000
    #define INF (1LL<<60)
    ll f[MN+5][MN+5];
    int x[MN+5],w[MN+5],q[MN+5],ql,qr,t[MN+5];
    int cal(int k,int n,int x,int y)
    {
        int l=x+1,r=n,mid,res=n+1;
        while(l<=r)
        {
            mid=l+r>>1;
            if(f[k][x]+f[mid][x]>f[k][y]+f[mid][y])l=mid+1;
            else res=mid,r=mid-1;
        }
        return res;
    }
    int main()
    {
        freopen("easyproblem.in","r",stdin);
        freopen("easyproblem.out","w",stdout);
        int n,k,i,j,l;
        n=read();k=read();
        if(k>=n)return 0*puts("0");
        for(i=1;i<=n;++i)x[i]=read(),w[i]=read();
        for(i=1;i<=n;++i)for(j=i;j--;)
            f[i][j]=f[i][j+1]+1LL*w[j+1]*(x[i]-x[j+1]);
        for(i=1;i<=n;++i)f[0][i]=INF;
        if(n<=300)
            for(l=1;l<=k;++l)for(i=l;i<=n;++i)for(f[l][i]=INF,j=l-1;j<i;++j)
                f[l][i]=min(f[l][i],f[l-1][j]+f[i][j]);
        else
            for(l=1;l<=k;++l)for(ql=0,qr=-1,i=l;i<=n;++i)
            {
                while(ql<qr&&(t[qr]=cal(l-1,n,i-1,q[qr]))<=t[qr-1])--qr;
                if(ql==qr)t[qr]=cal(l-1,n,i-1,q[qr]);q[++qr]=i-1;
                while(ql<qr&&t[ql]<=i)++ql;
                f[l][i]=f[l-1][q[ql]]+f[i][q[ql]];
            }
        cout<<f[k][n];
        fclose(stdin);fclose(stdout);return 0;
    }

    T3.你的三角形已如风中残烛

    题目大意:题名很劲爆,题意是这样的:给定一张n个点的无向图,选出若干个点,使得由这些点组成的三角形个数与选的点个数比值最大,输出方案。(n<=50)

    思路:我写的小数据暴搜,大数据自己构造几个比较优而且好找的解取最优输出,得分64。

    #include<cstdio>
    #include<cstdlib>
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 50
    int n,g[MN+5][MN+5],a[MN+5],an,u[MN+5];
    int px[MN*MN+5],py[MN*MN+5],cnt;
    double ans;
    void dfs(int x,int k,int s)
    {
        int i;
        if(x>n)
        {
            if((k?(double)s/k:0)>=ans)
            {
                ans=k?(double)s/k:0;
                for(an=0,i=1;i<=n;++i)if(u[i])a[++an]=i;
            }
            return;
        }
        u[x]=0;dfs(x+1,k,s);
        for(i=1;i<=cnt;++i)if(g[x][px[i]]&&g[x][py[i]])++s;
        for(i=1;i<x;++i)if(u[i]&&g[x][i])px[++cnt]=i,py[cnt]=x;
        u[x]=1;dfs(x+1,k+1,s);
        for(i=1;i<x;++i)if(u[i]&&g[x][i])--cnt;
    }
    void cal()
    {
        int i,j,s=0,k=0;
        for(cnt=0,i=1;i<=n;++i)if(u[i])
        {
            ++k;
            for(j=1;j<=cnt;++j)if(g[i][px[j]]&&g[i][py[j]])++s;
            for(j=1;j<i;++j)if(u[j]&&g[i][j])px[++cnt]=i,py[cnt]=j;
        }
        if((k?(double)s/k:0)>ans)
        {
            ans=k?(double)s/k:0;an=0;
            for(i=1;i<=n;++i)if(u[i])a[++an]=i;
        }
    }
    void sb()
    {
        int i,j,k,l;
        for(i=1;i<=n;++i)u[i]=1;cal();
        for(i=1;i<=n;++i)u[i]=0,cal(),u[i]=1;
        for(i=1;i<=1000;++i,cal())for(j=1;j<=n;++j)u[j]=rand()&1;
        for(i=1;i<=n;++i)for(j=i+1;j<=n;++j)for(k=j+1;k<=n;++k)
            if(g[i][j]&&g[j][k]&&g[k][i]){for(l=1;l<=n;++l)u[l]=0;u[i]=u[j]=u[k]=1;cal();}
        for(i=1;i<=n;++i)for(j=i+1;j<=n;++j)for(k=j+1;k<=n;++k)for(l=k+1;l<=n;++l)
            if(g[i][j]&&g[i][k]&&g[i][l]&&g[j][k]&&g[j][l]&&g[k][l])
                {for(int p=1;p<=n;++p)u[p]=0;u[i]=u[j]=u[k]=u[l]=1;cal();}
    }
    int main()
    {
        srand(23333);
        freopen("triangle.in","r",stdin);
        freopen("triangle.out","w",stdout);
        int i,j;
        n=read();
        for(i=1;i<=n;++i)for(j=1;j<=n;++j)g[i][j]=read();
        if(n<=20)dfs(1,0,0);
        else sb();
        printf("%d
    ",an);
        for(i=1;i<=an;++i)printf("%d ",a[i]);
        fclose(stdin);fclose(stdout);return 0;
    }
    View Code

    正解:二分答案后最大流,每个三角形建一个点,向T连1,组成该三角形的三个点向它连INF,每次S向点连二分出的答案,则若三角形连向T的边均满流则当前二分答案偏大,否则偏小。二分出答案后删掉所有从S开始只走还有流量的边能到的点,剩下的点即为方案。复杂度O(MaxFlow(n^3,n^3))。

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 50
    #define MV 19650
    #define ME 78450
    #define S MV+1
    #define T MV+2
    #define eps 1e-6
    #define INF 1e6
    struct edge{int nx,t;double w;}e[ME*2+5];
    int g[MN+5][MN+5],h[MV+5],en=1,q[MV+5],qn,d[MV+5],c[MV+5];
    inline void ins(int x,int y,double w)
    {
        e[++en]=(edge){h[x],y,w};h[x]=en;
        e[++en]=(edge){h[y],x,0};h[y]=en;
    }
    bool bfs()
    {
        int i,j;
        memset(d,0,sizeof(d));
        for(d[q[i=qn=0]=S]=1;i<=qn;++i)for(j=c[q[i]]=h[q[i]];j;j=e[j].nx)
            if(e[j].w>eps&&!d[e[j].t])d[q[++qn]=e[j].t]=d[q[i]]+1;
        return d[T];
    }
    double dfs(int x,double r)
    {
        if(x==T)return r;
        double k,u=0;
        for(int&i=c[x];i;i=e[i].nx)if(e[i].w>eps&&d[e[i].t]==d[x]+1)
        {
            k=dfs(e[i].t,r-u<e[i].w?r-u:e[i].w);
            u+=k;e[i].w-=k;e[i^1].w+=k;
            if(fabs(u-r)<eps)return u;
        }
        return d[x]=0,u;
    }
    void dfs(int x)
    {
        d[x]=1;
        for(int i=h[x];i;i=e[i].nx)if(!d[e[i].t]&&e[i].w>eps)dfs(e[i].t);
    }
    int main()
    {
        int n=read(),i,j,k,cnt=n;double l,r,mid,ans;
        for(i=1;i<=n;++i)ins(S,i,0);
        for(i=1;i<=n;++i)for(j=1;j<=n;++j)g[i][j]=read();
        for(i=1;i<=n;++i)for(j=1;j<i;++j)for(k=1;k<j;++k)
            if(g[i][j]&&g[j][k]&&g[k][i])ins(++cnt,T,1),ins(i,cnt,1),ins(j,cnt,1),ins(k,cnt,1);
        for(l=0,r=400,k=0;k<=50;++k)
        {
            mid=(l+r)/2;
            for(i=h[S];i;i=e[i].nx)e[i].w=mid,e[i^1].w=0;
            memset(d,0,sizeof(d));
            for(d[q[i=qn=0]=S]=1;i<=qn;++i)for(j=h[q[i]];j;j=e[j].nx)
            {
                if(!d[e[j].t])d[q[++qn]=e[j].t]=d[q[i]]+1;
                if(d[e[j].t]>d[q[i]])e[j].w+=e[j^1].w,e[j^1].w=0;
            }
            for(ans=0;bfs();)ans+=dfs(S,INF);
            for(i=h[T];i;i=e[i].nx)if(e[i].w>eps&&e[i].w<1-eps)break;
            (i?l:r)=mid;
        }
        memset(d,cnt=0,sizeof(d));dfs(S);
        for(i=1;i<=n;++i)if(!d[i])++cnt;
        printf("%d
    ",cnt);
        for(i=1;i<=n;++i)if(!d[i])printf("%d ",i);
    }
  • 相关阅读:
    Android 重写系统Crash处理类,保存Crash信息到SD卡 和 完美退出程序的方法
    LeetCode第二十四题-交换链表中节点值
    LeetCode第二十三题-合并n个有序链表
    LeetCode第二十二题-创建n对括号
    LeetCode第二十一题-对两个有序链表排序
    LeetCode第二十题-有效的括号
    LeetCode第十九题-链表节点的删除
    LeetCode第十八题-四数之和
    LeetCode第十七题-电话号码的字母组合
    LeetCode第十六题-找出数组中三数之和最接近目标值的答案
  • 原文地址:https://www.cnblogs.com/ditoly/p/20170323C.html
Copyright © 2011-2022 走看看