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;
}