AtCoder Beginner Contest 159(E、F


E - Dividing Chocolate

题意:

给一个n*m大小的巧克力,每个巧克力块有黑色和白色,
现在给你一个整数k,要求你切割巧克力,使得每一块的白色数量都小于等于k,
问最少切多少刀

每一刀都必须切到底,也就是一条线,
下图中左边的是合法的切法(一刀切到底),右边的是不合法的切法
在这里插入图片描述

数据范围:n<=10,m<=1e3,k<=n*m

解法:

观察到n只有10,因此二进制行的切法,check列的切法即可

code:

#include<bits/stdc++.h>
using namespace std;
int l[15],r[15],c[15],cc[15],tot;
char s[15][1005];
int n,m,k;
int cal(int st,int ed,int j){//st-ed行第j列
    int ans=0;
    for(int i=st;i<=ed;i++){
        if(s[i][j]=='1')ans++;
    }
    return ans;
}
int check(){
    for(int i=1;i<=tot;i++)c[i]=cc[i]=0;
    int ans=0;
    for(int j=1;j<=m;j++){//列
        int ok=1;
        for(int e=1;e<=tot;e++){
            cc[e]=cal(l[e],r[e],j);
            if(cc[e]>k)return -1;//无解
            if(c[e]+cc[e]>k){
                ok=0;
            }
        }
        if(ok){
            for(int e=1;e<=tot;e++)c[e]+=cc[e];
        }else{
            ans++;
            for(int e=1;e<=tot;e++)c[e]=cc[e];
        }
    }
    return ans;
}
signed main(){
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        scanf("%s",s[i]+1);
    }
    int ans=1e9;
    for(int i=0;i<(1<<(n-1));i++){
        int temp=0;
        for(int j=0;j<(n-1);j++)if(i>>j&1)temp++;
        tot=0;
        int last=1;
        for(int j=0;j<(n-1);j++){
            if(i>>j&1)tot++,l[tot]=last,r[tot]=j+1,last=j+2;
        }
        if(last<=n)tot++,l[tot]=last,r[tot]=n;
        int t=check();
        if(t==-1)continue;
        else temp+=t;
        ans=min(ans,temp);
    }
    cout<<ans<<endl;
    return 0;
}

F - Knapsack for All Segments

题意:

给一个长度为n的数组a,以及一个整数S
定义F(L,R)为区间[L,R]中和为S
对于1<=L<=R<=n,求F(L,R)的和,即所有区间的F的和

数据范围:n<=3e3,1<=a(i)<=3e3,S<=3e3

解法:

如果只是求某个[L,R]和为S的子序列个数,那么直接01背包求方案数就行了,复杂度是O(n)的
如果对于每个区间都这样计算一次显然不行。

考虑每个合法子序列的贡献,假设子序列的左右端点下标为st和ed,那么贡献为st*(n-ed+1)
枚举右端点ed,那么只需要知道满足以当前ed为右端点的左端点的和就行了

令d(i,j)为前i个数,子序列和为j的左端点的和,
如果当前a(i)加入之前的序列,那么d(i,j)=d(i-1,j)+d(i-1,j-a(i))
如果当前a(i)不加入之前的序列,那么d(i,a(i))+=i

dp的第一维可以优化掉

还有就是特判一下a(i)=s的情况

扫描二维码关注公众号,回复: 10554235 查看本文章

总结:贡献为a*b的可以枚举一个,想办法求另外一个

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=3e3+5;
const int mod=998244353;
int d[maxm];
int a[maxm];
signed main(){
    int n,s;
    cin>>n>>s;
    for(int i=1;i<=n;i++)cin>>a[i];
    int ans=0;
    for(int i=1;i<=n;i++){
        if(s>a[i]){
            ans=(ans+d[s-a[i]]*(n-i+1)%mod)%mod;
        }else if(s==a[i]){
            ans=(ans+i*(n-i+1)%mod)%mod;
        }
        for(int j=s;j>=a[i];j--){
            d[j]=(d[j]+d[j-a[i]])%mod;
        }
        d[a[i]]=(d[a[i]]+i)%mod;
    }
    cout<<ans<<endl;
    return 0;
}

发布了445 篇原创文章 · 获赞 37 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/105290189