集训队日常训练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\n",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\n",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\n",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\n",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\n",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\n",(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\n",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\n",ans);
    }
    
}
K.cpp

posted on 2019-05-26 10:57  大桃桃  阅读(392)  评论(0编辑  收藏  举报

导航