zoukankan      html  css  js  c++  java
  • 2017北京国庆刷题Day4 morning

    期望得分:0+40+30=70

    实际得分:0+10+10=20

     题目修改:只能由0变1,只能用一次操作

    大模拟

    #include<cstdio>
    #include<cstring>
    using namespace std;
    char s[2001];
    int len,n;
    int cnt[2001];
    bool solve1()
    {
        if(len!=n) return false;
        int num=0;
        for(int i=0;i<len;i++)
            if(s[i]=='1') num+=i+1;
        if(num%(n+1)==0)
        {
            puts(s);
            return true;
        }
        return false;
    }
    bool solve2()
    {
        if(len!=n) return false;
        int num=0;
        for(int i=0;i<len;i++)
            if(s[i]=='1') num+=i+1;
        for(int i=0;i<len;i++)
            if(s[i]=='1')
            {
                num-=(i+1);
                if(num%(n+1)==0) 
                {
                    for(int j=0;j<i;j++) putchar(s[j]);
                    putchar('0');
                    for(int j=i+1;j<len;j++) putchar(s[j]);
                    printf("
    ");
                    return true;
                }
                num+=(i+1);
            }
        return false;
    }
    bool solve3()
    {
        if(len<=n) return false;
        int num=0;
        for(int i=0;i<len;i++)
            if(s[i]=='1') num+=i+1,cnt[i+1]=cnt[i]+1;
            else cnt[i+1]=cnt[i];
        for(int i=0;i<len;i++)
            if(s[i]=='0')
            {
                num-=(cnt[len]-cnt[i]);
                if(num%(n+1)==0)
                {
                    for(int j=0;j<i;j++) putchar(s[j]);
                    for(int j=i+1;j<len;j++) putchar(s[j]);
                    printf("
    ");
                    return true;
                }
                num+=(cnt[len]-cnt[i]);
            }
            else
            {
                num-=(cnt[len]-cnt[i+1]);
                num-=(i+1);
                if(num%(n+1)==0)
                {
                    for(int j=0;j<i;j++) putchar(s[j]);
                    for(int j=i+1;j<len;j++) putchar(s[j]);
                    printf("
    ");
                    return true;
                }
                num+=(cnt[len]-cnt[i+1]);
                num+=(i+1);
            }
        return false;
    }
    bool solve4()
    {
        if(len>=n) return false;
        int num=0;
        for(int i=0;i<len;i++)
            if(s[i]=='1') num+=(i+1),cnt[i+1]=cnt[i]+1;
            else cnt[i+1]=cnt[i];
        for(int i=0;i<len;i++)
        {
            num+=cnt[len]-cnt[i];
            if(num%(n+1)==0)
            {
                for(int j=0;j<i;j++) putchar(s[j]);
                putchar('0');
                for(int j=i;j<len;j++) putchar (s[j]);
                printf("
    ");
                return true;
            }
            num+=i+1;
            if(num%(n+1)==0)
            {
                for(int j=0;j<i;j++) putchar(s[j]);
                putchar('1');
                for(int j=i;j<len;j++) putchar(s[j]);
                printf("
    ");
                return true;
            }
            num-=(i+1);
            num-=(cnt[len]-cnt[i]);
        }
        if(num%(n+1)==0) { printf("%s",s); printf("0
    ");return true; }
        if((num+len+1)%(n+1)==0) { printf("%s",s); printf("1
    "); return true; }
        return false;
    }
    int main()
    {
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        scanf("%d",&n);
        while(scanf("%s",s)!=EOF)
        {
            len=strlen(s);
            if(solve1()) continue;
            if(solve2()) continue;
            if(solve3()) continue;
            if(solve4()) continue;
            printf("-1
    ");
        }
    }
    View Code

    题目中要求选的数 %m 互不相同

    那么可以很自然的想到

    先在<m的数里选k个 ,使他们的和 s%m=n%m,那么还剩下n-s

    为了保证%m 不相同,所以 我们把剩下的n-s 分为 (n-s)/m 个 m,

    给这k个数分 m

    也就是说

    如果要换掉x,只能用和x 模m属于同一剩余系 的数换,所以 只能加 m的整数倍

    设f[i][j] 表示选了i个数,和为j,且选的i个数互不相同的方案数

    设g[i][j]表示把i个m分给j个数的方案数

    那么ans= Σ f[i][j] * g[(n-j)/m][i] * i !,  其中要求j%m=n%m

    这里要乘i的阶乘,因为 1 2 和 2 1 算作不同的方案 

    如何求f[i][j] ?

    很容易想到 f[i][j][k] 表示 选了i个数,和为j,选的数字中最大的为k的方案数

    这样是m^4,TLE

    其实可以压去第三维

    两维的缺陷是 如果顺序枚举i,枚举j,再枚举现在选哪个数,不能保证选的数%m互不相同

    因为对于同一个数k,可能f[i+1][j] 由 已经选了k的f[i][j-k]再选k转移而来

    解决的方法是

    先枚举当前选哪个数,再倒序枚举选了多少个数,再枚举这些数的和

    这样就保证了对于同一个数k,不会让 i+1 由 i 转移

    如何求g[i][j]?

    把i个东西分给j个人,显然是组合数

    C(i+j-1,j-1) 

    难道 还要逆元?

    其实不用 ,这个C 化开为:

        1*2* …… i+j-1

    ---------------------------------(这是分数线) 

    (1*2……j-1)*(1*2……*i)

    = ((i+1)*(i+2)……*(i+j-1))/((j-1)!)

    不要漏了 统计答案的时候还要乘上j! 所以分母消去只剩下个j

    求 (i+1)*(i+2)……*(i+j-1) 的时候,i 本身可能是 long long ,不要忘了先取模,防止 乘爆

    #include<cstdio>
    
    #define M 101
    
    using namespace std;
    
    typedef long long LL;
    
    const LL mod=905229641;
    
    int f[M][M*M/2];
    
    LL mul(LL a,LL b)
    {
        LL res=1;
        for(LL i=a;i<=b;i++) res*=i,res%=mod;
        return res;
    } 
    
    int main()
    {
        freopen("b.in","r",stdin);
        freopen("b.out","w",stdout);
        LL n; int m;
        scanf("%I64d%d",&n,&m);
        int mx=m*(m-1)/2;
        f[0][0]=1;
        for(int k=0;k<m;k++)
            for(int i=m;i;i--)
                for(int j=k;j<=mx;j++)
                    f[i][j]+=f[i-1][j-k],f[i][j]%=mod;
        int x=n%m; LL res,ans=0,y;
        for(int i=x;i<=mx && i<=n;i+=m)
        {
            y=(n-i)/m;
            for(int j=1;j<=m;j++)
                if(f[j][i])
                {
                    res=mul((y+1)%mod,(y+j-1)%mod);
                    res*=f[j][i]; res%=mod;
                    res*=j; res%=mod;
                    ans+=res,ans%=mod;
                }
        }
        printf("%I64d",ans);
    }
    View Code

    解决本题的突破点:

    哪一年种哪些地可以随意定

    dp[i] 表示 种过的最右边的地为i时的最大收益

    将所有的种地区间按左端点从左到右排序

    那么对于当前这个种地区间[l[i],r[i]]

    它的上一个种地区间 [l[j],r[j]],

    l[j]一定<=l[i]

    r[j]可能有三种情况

    ① r[j] < l[i] 此时第i块地 有全部的垦荒代价

    ② r[j]∈[l[i],r[i]) 此时第i块地 有 右边部分的垦荒代价

    ③ r[j]>=r[i] 此时第i块地 没有垦荒代价

    令sum[i]表示垦荒代价的前缀和,val[i]表示第i次垦荒的收益

    那么对应的状态转移方程:

    ① dp[r[i]]=max(dp[r[j]]+val[i]-(sum[r[i]]-sum[l[i]-1]))

    ② dp[r[i]]]=max(dp[r[j]]+val[i]-(sum[r[i]]-sum[r[j]]))

    ③ dp[r[j]]+=val[i]

    朴素的dp为O(n^2)

    可用线段树优化至nlogn 

    在 r[j]==r[i] 时,有很多细节

    线段树的没调出来

    30分 n^2代码

    #include<cstdio>
    #include<cstring>
    #include<iostream> 
    #include<algorithm>
    
    #define N 200001
    
    using namespace std;
    
    typedef long long LL;
    
    LL sum[N],dp[N];
    int vis[N];
    
    struct node
    {
        int l,r,p;
    }e[N];
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar();  }
    } 
    
    bool cmp(node p,node q)
    {
        if(p.l!=q.l) return p.l<q.l;
        return p.r<q.r;
    }
    
    int main()
    {
        freopen("c.in","r",stdin);
        freopen("c.out","w",stdout);
        int n,m,x; 
        read(n); read(m);
        for(int i=1;i<=n;++i) read(x),sum[i]=sum[i-1]+x;
        for(int i=1;i<=m;++i) read(e[i].l),read(e[i].r),read(e[i].p);
        sort(e+1,e+m+1,cmp);
        memset(dp,-127,sizeof(dp));
        for(int i=1;i<=m;i++)
        {
            LL tmp=-1e18; bool ok=false;
            dp[e[i].r]=max(dp[e[i].r],e[i].p-(sum[e[i].r]-sum[e[i].l-1]));
            tmp=dp[e[i].r];
            for(int j=i-1;j;j--)
                if(e[j].r<e[i].l) dp[e[i].r]=max(dp[e[i].r],dp[e[j].r]+e[i].p-(sum[e[i].r]-sum[e[i].l-1]));
                else if(e[j].r<e[i].r) dp[e[i].r]=max(dp[e[i].r],dp[e[j].r]+e[i].p-(sum[e[i].r]-sum[e[j].r]));
                else if(vis[e[j].r]!=i) // 一个e[i].p只能累计一次到一个e[j].r 里 
                {
                    if(e[j].r==e[i].r) ok=true;//e[i].r==e[j].r 时,r 可能被 前两种情况修改过,但累计的话只能是用没有修改过的 
                    else dp[e[j].r]+=e[i].p,vis[e[j].r]=i;
                }
             if(ok) dp[e[i].r]=max(dp[e[i].r],tmp+e[i].p);
        }
        LL ans=0;
        for(int i=1;i<=n;i++) ans=max(ans,dp[i]);
        printf("%I64d",ans);
    } 
    View Code

    std

    #include <cstdio>
    #include <cctype>
    #include <memory.h>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long qw;
    
    #ifdef WIN32
    #define lld "%I64d"
    #else
    #define lld "%lld"
    #endif
    
    int nextInt() {
        int s = 0, d;
        bool nag = 0;
        do {
            d = getchar();
            if (d == '-')
                nag = 1;
        } while (!isdigit(d));
        do
            s = s * 10 + d - 48, d = getchar();
        while (isdigit(d));
        return nag ? -s : s;
    }
    
    struct seg {
        int l, r;
        qw v, z;
        seg *ls, *rs;
    };
    struct obj {
        int l, r, v;
    };
    
    inline bool cmpObj(const obj& a, const obj& b) {
        return (a. l < b. l) || (a. l == b. l && a. r < b. r);
    }
    
    const int maxn = 200009;
    const qw inf = 0x3f3f3f3f3f3f3f3fLL;
    
    int n, m;
    obj q[maxn];
    qw s[maxn], ans;
    seg *rtf, *rtc, *sp;
    
    #define mid(p) ((p->l+p->r)>>1)
    
    seg *sgtBuild(int l, int r) {
        seg *p = sp ++;
        p-> v = - inf;
        p-> z = 0;
        p-> l = l;
        p-> r = r;
        if (l + 1 < r) {
            p-> ls = sgtBuild(l, mid(p));
            p-> rs = sgtBuild(mid(p), r);
        }
        return p;
    }
    
    void sgtChg(seg* p, int p0, qw v0) {
        if (p-> l + 1 == p-> r)
            p-> v = max(p-> v, v0);
        else {
            if (p0 < mid(p))
                sgtChg(p-> ls, p0, v0 - p-> z);
            else
                sgtChg(p-> rs, p0, v0 - p-> z);
            p-> v = max(p-> ls-> v, p-> rs-> v) + p-> z;
        }
    }
    
    qw sgtQry(seg* p, int l, int r) {
        if (l >= r)
            return -inf;
        else if (p-> l == l && p-> r == r)
            return p-> v;
        else if (r <= mid(p))
            return sgtQry(p-> ls, l, r) + p-> z;
        else if (l >= mid(p))
            return sgtQry(p-> rs, l, r) + p-> z;
        else
            return max(sgtQry(p-> ls, l, mid(p)), sgtQry(p-> rs, mid(p), r)) + p-> z;
    }
    
    void sgtLazy(seg* p, int l, qw z0) {
        if (p-> v == -inf)
            return;
        else if (p-> l == l)
            p-> v += z0, p-> z += z0;
        else {
            if (l < mid(p)) {
                sgtLazy(p-> ls, l, z0);
                sgtLazy(p-> rs, mid(p), z0);
            }
            else
                sgtLazy(p-> rs, l, z0);
            p-> v = max(p-> ls-> v, p-> rs-> v) + p-> z;
        }
    }
    
    int main() {
    //    freopen("c.in","r",stdin);
    //    freopen("c.out","w",stdout);
        sp = new seg[maxn * 6];
        n = nextInt();
        m = nextInt();
        rtf = sgtBuild(0, n + 2);
        rtc = sgtBuild(0, n + 2);
        s[0] = 0;
        for (int i = 1; i <= n; i ++)
            s[i] = s[i - 1] + nextInt();
        for (int i = 0; i < m; i ++) {
            q[i]. l = nextInt();
            q[i]. r = nextInt();
            q[i]. v = nextInt();
        }
        sort(q, q + m, cmpObj);
        ans = 0;
        for (int i = 0; i < m; i ++) {
            qw res0 = max(sgtQry(rtf, 0, q[i]. l), 0LL) - s[q[i]. r] + s[q[i]. l - 1];
            qw res1 = sgtQry(rtc, q[i]. l, q[i]. r + 1) - s[q[i]. r];
            qw res = max(max(res0, res1), sgtQry(rtf, q[i]. r, n + 1)) + q[i]. v;
            sgtLazy(rtf, q[i]. r, q[i]. v);
            sgtLazy(rtc, q[i]. r, q[i]. v);
            sgtChg(rtf, q[i]. r, res);
            sgtChg(rtc, q[i]. r, res + s[q[i]. r]);
            ans = max(ans, res);
            printf("%I64d %I64d
    ",res,ans);
        }
        printf(lld "
    ", ans);
    }
    View Code

    没跳出来&&不想调的线段树

    #include<cstdio>
    #include<cstring>
    #include<iostream> 
    #include<algorithm>
    
    #define N 200001
    
    using namespace std;
    
    typedef long long LL;
    
    LL sum[N];
    
    LL mx1[N<<2],mx2[N<<2],f[N<<2];
    
    LL t1,t2;
    
    struct node
    {
        int l,r,p;
    }e[N];
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar();  }
    } 
    
    bool cmp(node p,node q)
    {
        if(p.l!=q.l) return p.l<q.l;
        return p.r<q.r;
    }
    
    void change(int k,int l,int r,int pos,LL w,int ty)
    {
        if(l==r)
        {
            if(ty==1) mx1[k]=max(mx1[k],w);
            else mx2[k]=max(mx2[k],w);
            return;
        } 
        int mid=l+r>>1;
        if(pos<=mid) change(k<<1,l,mid,pos,w,ty);
        else change(k<<1|1,mid+1,r,pos,w,ty);
        mx1[k]=max(mx1[k<<1],mx1[k<<1|1])+f[k];
        mx2[k]=max(mx2[k<<1],mx2[k<<1|1])+f[k];
    }
    
    int query(int k,int l,int r,int opl,int opr,int ty)
    {
        if(l>=opl && r<=opr)
        {
            if(ty==1) return max(t1,mx1[k]);
            return max(t2,mx2[k])a;
        }
        int mid=l+r>>1;
        if(opr<=mid) return query(k<<1,l,mid,opl,opr,ty)+f[k];
        if(opr>mid) return query(k<<1|1,mid+1,r,opl,opr,ty)+f[k];
        return max(query(k<<1,l,mid,opl,opr,ty),query(k<<1|1,mid+1,r,opl,opr,ty))+f[k];
    }
    
    void add(int k,int l,int r,int pos,int w)
    {
        if(l==pos) 
        {
            f[k]+=w;
            mx1[k]+=w;
            mx2[k]+=w;
            return;
        }
        int mid=l+r>>1;
        if(pos<=mid) add(k<<1,l,mid,pos,w),add(k<<1|1,mid+1,r,mid+1,w);
        else add(k<<1|1,mid+1,r,pos,w);
        mx1[k]=max(mx1[k<<1],mx1[k<<1|1])+f[k];
        mx2[k]=max(mx2[k<<1],mx2[k<<1|1])+f[k];
    }
    
    int main()
    {
    //    freopen("8.in","r",stdin);
    //    freopen("c.out","w",stdout);
        int n,m,x; LL ans=0;
        read(n); read(m);
        for(int i=1;i<=n;++i) read(x),sum[i]=sum[i-1]+x;
        for(int i=1;i<=m;++i) 
         read(e[i].l),read(e[i].r),read(e[i].p);
        sort(e+1,e+m+1,cmp);
        memset(mx2,-127,sizeof(mx2));
        memset(mx1,-127,sizeof(mx1));
        LL now;
        for(int i=1;i<=m;i++)
        {
            t1=query(1,1,n,e[i].l,e[i].r,1);//2 
            t2=query(1,1,n,e[i].r,n,2);
            now=t1+e[i].p-sum[e[i].r];//2
            now=max(now,t2+e[i].p);
            t2=query(1,1,n,1,e[i].l,2);
            now=max(now,t2+e[i].p-sum[e[i].r]+sum[e[i].l-1]);//1
            ans=max(ans,now);
            add(1,1,n,e[i].r,e[i].p);
            change(1,1,n,e[i].r,now+sum[e[i].r],1);
            change(1,1,n,e[i].r,now,2);
            
            printf("%I64d %I64d
    ",now,ans);
        } 
        printf("%I64d",ans); 
    } 
    View Code
  • 相关阅读:
    重定义自定义类型
    范式
    管理
    JVM调优[转]
    I/O相关的等待事件
    等待事件监测性能瓶颈
    Shared pool
    SQL*Plus和PL/SQL
    Oracle优化器和执行计划
    10053事件
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7648176.html
Copyright © 2011-2022 走看看