zoukankan      html  css  js  c++  java
  • 集训队日常训练20180525-DIV1

    A.2805

    N*M的图,每次浇水(X1,Y1)-(X2,Y2)围成的矩形,问最后有多少点被浇水了。

    暴力。

    #include<bits/stdc++.h>
    using namespace std;
    
    bool g[245][245];
    int main()
    {
        int X,Y,I;
        cin>>X>>Y>>I;
        while(I--)
        {
            int X1,Y1,X2,Y2;
            cin>>X1>>Y1>>X2>>Y2;
            for(int i=X1;i<=X2;i++)
                for(int j=Y1;j<=Y2;j++)
                    g[i][j]=1;
        }
        int ans=0;
        for(int i=1;i<=X;i++)
            for(int j=1;j<=Y;j++)
                ans+=g[i][j];
        printf("%d",ans);
        return 0;
    }
    A.cpp

    这个题数据可以出到N,M<=5000,复杂度O(n^2)。做法二维差分约束。

    B.2366

    公司每月盈利s,亏损d,连续5个月一次报表都为亏损,问一年最多可以盈利多少。

    构造题。

    如果d>4*s,那么ssssdssssdss,每连续5个月都为亏

    如果d>3/2*s,那么sssddsssddss。

    如果d>2/3*s,那么ssdddssdddss。

    如果d>1/4*s,那么sddddsddddsd。

    否则dddddddddddd。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define ll __int64
    int main()
    {
        ll s,d,val;
        while(cin>>s>>d)
        {
            ///+s -d
            if(d>4*s)val=10*s-2*d;
            else if(d>1.5*s)val=8*s-4*d;
            else if(d>2./3*s)val=6*s-6*d;
            else if(d>0.25*s)val=3*s-9*d;
            else val=0;
            if(val>0)cout<<val<<endl;
            else cout<<"Deficit"<<endl;
        }
        return 0;
    }
    B.cpp

    C.2282

    给若干个关系,a比b重,问那些珠子不可能是中值。

    弗洛伊德Floyd,g[i][j]=1代表i比j重,f[i][j]=1代表i比j轻。

    由于数据的问题,会出现环路比如1比2重,2比3重,3比1重。

    #include<bits/stdc++.h>
    using namespace std;
    
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            int n,m;
            cin>>n>>m;
            int g[105][105]={0},f[105][105]={0};
            for(int i=1;i<=m;i++)
            {
                int u,v;
                cin>>u>>v;
                g[u][v]=1;
                f[v][u]=1;
            }
            for(int k=1;k<=n;k++)
                for(int i=1;i<=n;i++)
                    for(int j=1;j<=n;j++)
                        g[i][j]|=g[i][k]&g[k][j],
                        f[i][j]|=f[i][k]&f[k][j];
            int ans=0;
            for(int i=1;i<=n;i++)
            {
                int suml=0,sumr=0;
                for(int j=1;j<=n;j++)
                {
                    if(i==j)continue;
                    if(g[i][j])suml++;
                    if(f[i][j])sumr++;
                }
                if(suml>=(n+1)/2||sumr>=(n+1)/2)ans++;
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    C.cpp

    D.4427

    N个孩子,M种颜色,a[i]代表i颜色的大理石数目,小孩只喜欢相同颜色的大理石。小孩的嫉妒值为给一个孩子的最大大理石数量。如何分,嫉妒值最小,输出最小的嫉妒值。

    二分嫉妒值,看人数是否能达到n。

    #include <bits/stdc++.h>
    using namespace std;
    int a[300005],n,m;
    bool check(int x)
    {
        int ans=0;
        for(int i=0;i<m;i++)
            ans+=(a[i]+x-1)/x;
        return ans>n;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++)
            scanf("%d",&a[i]);
        int l=1,r=1e9,ans=-1;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(!check(mid)) ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%d
    ",ans);
        return 0;
    }
    D.cpp

    E.3573

    N个项目D[i]代表D[i]分钟完成,V[i]代表价值,每分钟只能做一个项目,问M分钟内做出的最大价值。

    贪心+优先队列。

    首先按D排序从小到大,D相同按V从大到小排序。

    如果a[i].d>qu.size()&&qu.size()<m说明有空可以放,直接放入。

    否则如果a[i].v>优先队列最小的v,就换掉。

    最后统计优先队列里所有v的和。

    #include<bits/stdc++.h>
    using namespace std;
    struct T
    {
        int d,v;
        bool operator<(const T &t)const{
            return d<t.d||(d==t.d&&v>t.v);
        }
    }a[100005];
    priority_queue<int,vector<int>,greater<int> >qu;
    int main()
    {
        int n,m;
        while(~scanf("%d%d",&n,&m))
        {
            for(int i=0;i<n;i++)
                scanf("%d%d",&a[i].d,&a[i].v);
            sort(a,a+n);
            for(int i=0;i<n;i++)
            {
                if(a[i].d>qu.size()&&qu.size()<m) qu.push(a[i].v);
                else
                {
                    if(!qu.empty()&&a[i].v>qu.top())
                        qu.pop(),qu.push(a[i].v);
                }
            }
            int ans=0;
            while(!qu.empty())
                ans+=qu.top(),qu.pop();
            printf("%d
    ",ans);
        }
        return 0;
    }
    E.cpp

    F.2283

    N个数,每次取连续K个,取不相交的三段,问最大和。

    dp[i][j]代表当前点i取了j次的最大和。

    需要用前缀和优化dp(快速算出[i,j]的和)。

    dp[i][j]=max(max(dp[i][j],dp[i-1][j]),dp[i-k][j-1]+pre[i]-pre[i-k]);

    #include <bits/stdc++.h>
    using namespace std;
    const int N=50005;
    int dp[N][4],pre[N];
    int main()
    {
        int T,n,k;
        scanf("%d",&T);
        while(T--)
        {
            memset(dp,0,sizeof dp);
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
                scanf("%d",&pre[i]),pre[i]+=pre[i-1];
            scanf("%d",&k);
            for(int i=k;i<=n;i++)
                for(int j=0;j<=3;j++)
                {
                    if(j) dp[i][j]=max(dp[i][j],dp[i-k][j-1]+pre[i]-pre[i-k]);
                    dp[i][j]=max(dp[i][j],dp[i-1][j]);
                }
            printf("%d
    ",dp[n][3]);
        }
        return 0;
    }
    F.cpp

    G.2586

    N盏灯,初始都为灭。对于0操作,[L,R]取反。对于1操作,输出[L,R]亮灯的数量。

    线段树区间取反+区间求和。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e5+5;
    int cnt[N<<2];
    int lazy[N<<2];
    void pushdown(int l,int r,int rt)
    {
        if(!lazy[rt])return;
        lazy[rt<<1]^=1;
        lazy[rt<<1|1]^=1;
        int mid=(l+r)>>1;
        cnt[rt<<1]=mid-l+1-cnt[rt<<1];
        cnt[rt<<1|1]=r-mid-cnt[rt<<1|1];
        lazy[rt]=0;
    }
    void update(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            lazy[rt]^=1;
            cnt[rt]=r-l+1-cnt[rt];
            return;
        }
        int mid=(l+r)>>1;
        pushdown(l,r,rt);
        if(L<=mid)update(L,R,l,mid,rt<<1);
        if(R>mid)update(L,R,mid+1,r,rt<<1|1);
        cnt[rt]=cnt[rt<<1]+cnt[rt<<1|1];
    }
    int query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)return cnt[rt];
        int mid=(l+r)>>1,ans=0;
        pushdown(l,r,rt);
        if(L<=mid)ans+=query(L,R,l,mid,rt<<1);
        if(R>mid)ans+=query(L,R,mid+1,r,rt<<1|1);
        cnt[rt]=cnt[rt<<1]+cnt[rt<<1|1];
        return ans;
    }
    int main()
    {
        int n,m,op,l,r;
        scanf("%d%d",&n,&m);
        while(m--)
        {
            scanf("%d%d%d",&op,&l,&r);
            if(op==0)update(l,r,1,n,1);
            else printf("%d
    ",query(l,r,1,n,1));
        }
        return 0;
    }
    G.cpp

    H.2593

    N个二进制数,Q个查询。对于每个查询s,输出满足条件前min(len[i],s)个数都相同的数的个数(i是q的前缀或者q是i的前缀)。

    由于读入过大,建议使用快读。

    字典树,sum[rt]表示字典树节点编号rt是多少个串的结尾,ss[rt]表示字典树节点编号rt是多少个串的非结尾。

    每次查询,如果查询串未到结尾就是ans+=ss[rt],如果结尾就是ans+=ss[rt]+sum[rt]。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define maxn 500005
    int Scan()
    {
        int res = 0, ch, flag = 0;
        if((ch = getchar()) == '-')   flag = 1;
        else if(ch >= '0' && ch <= '9')
        res = ch - '0';
        while((ch = getchar()) >= '0' && ch <= '9' )
        res = res * 10 + ch - '0';
        return flag ? -res : res;
    }
    int tot=1;
    int trie[maxn][2],sum[maxn],ss[maxn];
    bool isw[maxn]; //查询整个单词用
    int num;
    void insert()
    {
        int k;
        scanf("%d",&k);
        int rt=1;
        for(int i=1;i<=k;i++)
        {
            int x=Scan();
            if(trie[rt][x]==0) trie[rt][x]=++tot;
            int g=trie[rt][x];
            if(i!=k) sum[g]++;
            else ss[g]++;
            rt=trie[rt][x];//为下个字母的插入做准备
        }
    }
    void find()
    {
        int k;
        scanf("%d",&k);
        int rt=1;
        int g=1;
        for(int i=1;i<=k;i++)
        {
            int x=Scan();
            if(trie[rt][x]==0||g==0)
            {
                g=0;
                continue;
            }
            int tot=trie[rt][x];
            if(i!=k)
            num+=ss[tot];
            else num+=sum[tot]+ss[tot];
            rt=trie[rt][x];//为查询下个字母做准备
        }
        //查询整个单词时,应该return isw[rt]
    }//查找
    int main()
    {
        int n,m,k;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) insert();
        for(int i=1;i<=m;i++)
        {
            num=0;
            find();
            printf("%d
    ",num);
        }
    }
    H.cpp

    I.2616

    N个数取任意个满足和是F的倍数。

    背包dp,dp[i][j]表示选到前i件物品,%m的余数为j的方案数。

    初始条件dp[i][x]=1。

    转移:dp[i][j]+=dp[i-1][j]+dp[i-1][((j-x)%m+m)%m];

    #include <bits/stdc++.h>
    using namespace std;
    const int MD=100000000;
    int dp[2005][1005];
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        dp[0][0]=1;
        for(int i=1,x;i<=n;i++)
        {
            scanf("%d",&x);
            for(int j=0;j<m;j++)
                dp[i][j]=dp[i-1][j];
            for(int j=0;j<m;j++)
                dp[i][j]=(dp[i][j]+dp[i-1][((j-x)%m+m)%m])%MD;
        }
        printf("%d
    ",(dp[n][0]-1+MD)%MD);
        return 0;
    }
    I.cpp

    J.3521

    输出所有N位数且每次移除最后一个数也都是质数的数。例如7331:7331,733,73,7都是质数。

    深搜。

    #include<stdio.h>
    int n;
    int p(int a)
    {
        if(a==1)return 0;
        for(int i=2;i*i<=a;i++)
            if(a%i==0)
                return 0;
        return 1;
    }
    void dfs(int s,int m)
    {
        for(int i=1;i<=9;i++)
        {
            if(p(m*10+i))
            {
                if(n==s)printf("%d
    ",m*10+i);
      dfs(s+1,m*10+i);
            }
        }
    }
    int main()
    {
        scanf("%d",&n);
        dfs(1,0);
        return 0;
    }
    J.cpp

    K.2906

    N*M的01矩阵,求最大全1子矩阵。

    这里读入数据较大,建议使用快读。

    王知昆《浅谈用极大化思想解决最大子矩阵问题》

    https://www.cnblogs.com/Konjakmoyu/p/5787633.html

    #include<cstdio>
    #define N 2005
    int n,m,i,j,ans,l[N],r[N],h[N],lmax,rmax,a[N][N];
    int main(){
        while(~scanf("%d%d",&n,&m)){
            for(ans=0,i=1;i<=n;i++)for(j=1;j<=m;j++)scanf("%d",&a[i][j]);
            for(i=1;i<=m;i++)h[i]=0,l[i]=1,r[i]=m;
            for(i=1;i<=n;i++){
                for(lmax=j=1;j<=m;j++)if(a[i][j]){
                    h[j]++;
                    if(lmax>l[j])l[j]=lmax;
                }else h[j]=0,l[j]=1,r[j]=m,lmax=j+1;
                for(rmax=j=m;j;j--)if(a[i][j]){
                    if(rmax<r[j])r[j]=rmax;
                    if((r[j]-l[j]+1)*h[j]>ans)ans=(r[j]-l[j]+1)*h[j];
                }else rmax=j-1;
            }
            printf("%d
    ",ans);
        }
        
    }
    K.cpp
  • 相关阅读:
    AtCoder Grand Contest 030题解
    Codeforces Round #542 (Div. 1) 题解
    ZJOI2019赛季回顾
    UOJ #450「集训队作业2018」复读机
    「IOI2018」狼人
    APIO2019游记
    BZOJ4314 倍数?倍数!
    伯努利数学习笔记&&Luogu P3711 仓鼠的数学题
    Codeforces Round #541 (Div. 2)题解
    UOJ #460 新年的拯救计划
  • 原文地址:https://www.cnblogs.com/taozi1115402474/p/10925386.html
Copyright © 2011-2022 走看看