• XJOI contest800


    第一题

    题目描述:

    数据范围:

    0<=n, m<=10^5.

    具体思路:树状数组

    开两个,一个记录左端点,另一个记录右端点,然后答案就是总数减去左端点大于r的和右端点小于l的

    AC代码

    #include <cstdio>
    #include <cstring>
    const int MAXN=100010;
    int n,m;
    int a[2][MAXN],q,l,r,tot;
    int lowbit(int x){return x&(-x);}
    void add(int k,int x)
    {
        while (x<=n)a[k][x]++,x+=lowbit(x);
    }
    int sum(int k,int x)
    {
        int ans=0;
        while (x>=1)ans+=a[k][x],x-=lowbit(x);
        return ans;
    }
    int main()
    {
        scanf("%d%d",&n,&m);n++;
        for (int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&q,&l,&r);
            if (q==1)add(0,l),add(1,r),tot++;
            else printf("%d
    ",sum(0,r)-sum(1,l-1));
        }
    }

    第二题

    题目描述:

    数据范围:
    总人数 K<=50。
    每个背包的容量 V<=5000。
    物品种类数 N<=200。
    其它正整数都不超过 5000。
    输入数据保证存在满足要求的方案。

    具体思路:

    这不一眼DP题嘛

    还是01背包呢

    但难在要求出最优的k个解

    sof[i][j]表示容量为i的包的j优解

    然后转移的时候就是两个合并一下,保留前k个

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    int v[5010],w[5010],f[5010][60],t[5010];
    int nowj,nowjv,i,j,k,n,vmx,num,h,m,sum,sum1,sum2,total;
    int main()
    {
        scanf("%d%d%d",&k,&vmx,&n);
        for (i=1;i<=n;i++)
        scanf("%d%d",&v[i],&w[i]);
        for (i=0;i<=vmx;i++)
        {
            for (j=1;j<=k;j++)
            f[i][j]=-100000000;
            f[i][0]=0; 
        }
        f[0][0]=1;
        f[0][1]=0; 
        for  (i=1;i<=n;i++)
        {
            for (j=vmx-v[i];j>=0;j--)
            {
                for (h=1;h<=f[j+v[i]][0];h++)t[h]=f[j+v[i]][h]; 
                sum1=f[j][0]; sum2=f[j+v[i]][0];sum=sum1+sum2; 
                if (sum>k) sum=k;
                f[j+v[i]][0]=sum; 
                nowj=1,nowjv=1;
                for (h=1;h<=sum;h++)
                {
                    if (((f[j][nowj]+w[i]>t[nowjv]) &&(nowj<=sum1)) ||(nowjv>sum2))
                    
                    f[j+v[i]][h]=f[j][nowj]+w[i],nowj++;
                    
                    else f[j+v[i]][h]=t[nowjv],nowjv++;    
                }
            }
        }
        total=0;
        for (i=1;i<=f[vmx][0];i++)
        total+=f[vmx][i];
        printf("%d",total);
    }

    第三题

    题目描述:

    数据范围:

    药水种类 N<=60。
    配制方法数 M<=240。
    初始的金币数 V<=1000。
    每天可施的魔法数 K<=30。

    具体思路:今天DP题很多啊

    这个题要三次次dp

    f[i][j]表示用i次膜法造出j号膜药的最小花费

    然后每次转移也是一次dp(就是这个配制膜药的方法的每个原料共用i-1次膜法的最小花费)

    然后狂扫一下f[i][j]把有意义的方案存下来(就是用的金币比直接买少的)

    最后dp[i][j]表示用i次膜法,j个金币,可以得到的最大利润

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=65,M=345,V=1010,K=35;
    vector <int> s[1000];
    int n,m,v,k,g[400][800],sell[1000],buy[1000],x,y,tf[800][400],z;
    int top,w[200000][4],f[80][2000];
    int calc(vector <int>&a,int k)
    {
        int n=a.size()-1;
        for (int i=0;i<=n;++i) for (int j=0;j<=k;++j) tf[i][j]=1e5;
        tf[0][0]=0;
        for (int i=1;i<=n;++i)
            for (int j=0;j<=k;++j)
                for (int l=0;l<=j;++l)
                tf[i][j]=min(tf[i][j],tf[i-1][j-l]+g[l][a[i]]);
        return tf[n][k];
    }
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&v,&k);
        for (int i=1;i<=n;i++)scanf("%d%d",&sell[i],&buy[i]);
        for (int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            s[i].push_back(x);
            for (int j=1;j<=y;j++)scanf("%d",&z),s[i].push_back(z);
        }
        memset(g,0x3f,sizeof(g));
        for (int i=1;i<=n;i++)g[0][i]=sell[i];
        for (int i=1;i<=k;i++)
            for (int j=1;j<=m;j++)
            g[i][s[j][0]]=min(g[i][s[j][0]],calc(s[j],i-1));
        for (int i=0;i<=k;i++)
            for (int j=1;j<=n;j++)
            if(g[i][j]<=buy[j])top++,w[top][0]=i,w[top][1]=g[i][j],w[top][2]=buy[j]-g[i][j];
        int ans=0;
        for (int i=0;i<=k;i++)
            for (int j=0;j<=v;j++)
            {
                for (int hh=1;hh<=top;hh++)
                    if((i-w[hh][0])>=0&&(j-w[hh][1])>=0)
                    f[i][j]=max(f[i][j],f[i-w[hh][0]][j-w[hh][1]]+w[hh][2]);
                ans=max(ans,f[i][j]);
            }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    int a=5,则 ++(a++)的值是?
    C中文件操作说明
    最大子序列和 o(n)
    括号匹配
    DOM、SAX、JDOM、DOM4J四种XML解析方法PK
    java中的trim()
    SAX解析XML
    ConcurrentHashMap完全解析(jdk6/7,8)
    为什么推荐Zookeeper作注册中心
    分布式锁的三种实现方式
  • 原文地址:https://www.cnblogs.com/Orange-User/p/7598630.html
Copyright © 2020-2023  润新知