思路:强模拟…
思路:dp,先算总方案数,再将对应得位置判一下。
思路:看过题意,应该条件反射出二分答案,又因为n=2,也就是说,要么第1行画到i位置,第2行画到j位置,或者同时画到k位置。就很容易想到dp
每一次check时的dp,有很多是冗余的,便可预处理出来。这样达到的效果就应当于跳着画。
#include
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define INF 0x3f3f3f3f
#define LL long long
#define N 20005
#define M 105
using namespace std;
int n,m;
LL tot;
int A[2][N];
struct p20{
int sum[3][N];
bool dp[200][200];
bool check(LL x){
memset(dp,0,sizeof(dp));
dp[0][0]=1;
REP(l,1,m)DREP(i,n,0)DREP(j,n,0){
if(!dp[i][j])continue;
if(i==j){
REP(k,i+1,n){
if(sum[2][k]-sum[2][i]>x)break;
dp[k][k]=1;
}
}
REP(k,i+1,n){
if(sum[0][k]-sum[0][i]>x)break;
dp[k][j]=1;
}
REP(k,j+1,n){
if(sum[1][k]-sum[1][j]>x)break;
dp[i][k]=1;
}
}
return dp[n][n];
}
void solve(){
REP(i,0,1)REP(j,1,n)sum[i][j]+=sum[i][j-1]+A[i][j];
REP(i,1,n)sum[2][i]+=sum[0][i]+sum[1][i];
LL L=tot/m,R=tot,ans;
while(L<=R){
LL mid=(L+R)>>1;
if(check(mid))ans=mid,R=mid-1;
else L=mid+1;
}
cout<sum[3][505];
bool dp[750][750];
bool check(LL mx){
memset(dp,0,sizeof(dp));
dp[0][0]=1;
REP(l,1,m)DREP(i,n,0)DREP(j,n,0){
if(!dp[i][j])continue;
if(i==j){
int k=upper_bound(sum[2]+i,sum[2]+n+1,sum[2][i]+mx)-sum[2]-1;
dp[k][k]=1;
}
int k=upper_bound(sum[0]+i,sum[0]+n+1,sum[0][i]+mx)-sum[0]-1;
if(k>j)dp[j][j]=1;
dp[k][j]=1;
k=upper_bound(sum[1]+j,sum[1]+n+1,sum[1][j]+mx)-sum[1]-1;
if(k>i)dp[i][i]=1;
dp[i][k]=1;
}
return dp[n][n];
}
void solve(){
REP(i,0,1)REP(j,1,n)sum[i][j]+=sum[i][j-1]+A[i][j];
REP(i,1,n)sum[2][i]+=sum[1][i]+sum[0][i];
LL L=tot/m,R=tot,ans=0;
while(L<=R){
LL mid=(L+R)>>1;
if(check(mid))ans=mid,R=mid-1;
else L=mid+1;
}
cout<int dp[N];
bool check(LL x){
memset(dp,INF,sizeof(dp));
dp[0]=0;
REP(i,1,n){
int s0=0,s1=0,cnt=0;
DREP(j,i,1){
if(s0+A[0][j]>x)cnt++,s0=0;
if(s1+A[1][j]>x)cnt++,s1=0;
s0+=A[0][j],s1+=A[1][j];
dp[i]=min(dp[i],dp[j-1]+cnt+(s0>0)+(s1>0));
}
int s2=0;cnt=0;
DREP(j,i,1){
if(s2+A[0][j]+A[1][j]>x)cnt++,s2=0;
s2+=A[0][j]+A[1][j];
if(s2>x)break;
dp[i]=min(dp[i],dp[j-1]+cnt+(s2>0));
}
if(dp[i]>m)return 0;
}
return dp[n]<=m;
}
void solve(){
LL L=tot/m,R=tot,ans=0;
while(L<=R){
LL mid=(L+R)>>1;
if(check(mid))ans=mid,R=mid-1;
else L=mid+1;
}
cout<int dp[N],sum[3][N],nxt[3][N];
void chkmin(int &x,int y){if(x>y)x=y;}
bool check(LL x){
memset(dp,63,sizeof(dp));
dp[0]=0;
REP(i,0,2){
int L=1,R=1;
while(L<=n){
while(R<=n && sum[i][R]-sum[i][L-1]<=x)R++;
nxt[i][L]=R-1;
L++;
}
}
REP(i,0,n-1){
if(dp[i]==INF)continue;
int cnt=2,a=nxt[0][i+1],b=nxt[1][i+1];
chkmin(dp[nxt[2][i+1]],dp[i]+1);
while(a!=n || b!=n){
chkmin(dp[min(a,b)],dp[i]+cnt);
if(a0][a+1];
else b=nxt[1][b+1];
cnt++;
if(cnt+dp[i]>m)break;
}
if(a==n && b==n)chkmin(dp[n],dp[i]+cnt);
if(dp[n]<=m)return 1;
}
return dp[n]<=m;
}
void solve(){
REP(i,0,1)REP(j,1,n)sum[i][j]+=sum[i][j-1]+A[i][j];
REP(i,1,n)sum[2][i]+=sum[1][i]+sum[0][i];
LL L=1,R=tot,ans=0;
while(L<=R){
LL mid=(L+R)>>1;
if(check(mid))ans=mid,R=mid-1;
else L=mid+1;
}
cout<int main(){
scanf("%d%d",&n,&m);
REP(i,0,1)REP(j,1,n)scanf("%d",&A[i][j]),tot+=A[i][j];
p100.solve();
return 0;
}
小结:今天第一题题目看错,我也无fuck可说…总体就是炸了。