[BZOJ1044] [HAOI2008] 막대기 분할(2점+욕심+dp)
제목 설명
전송문
제목의 뜻: n개의 나무 막대기가 있고, i개의 나무 막대기의 길이는 리이며, n개의 나무 막대기는 순서대로 연결되어 총 n-1개의 연결부분이 있다.현재 최대 m개의 연결부를 잘라낼 수 있습니다. 베어낸 후 n개의 나무 막대기는 여러 단락으로 나뉘어져 있습니다. 총 길이가 가장 큰 단락의 길이를 충족시키고 몇 가지 베어내는 방법을 출력하여 총 길이가 가장 큰 단락의 길이를 최소화해야 합니다.결과mod 10007을 생성합니다.
문제풀이
첫 번째 질문은 욕심+2점 판정으로 답을 판정한 후 dp로 한 번 묻는다. f(i, j)는 i칼을 베었다는 뜻으로 j번째 방안수를 베었다. 단조롭게 한 번 훑어보고 i번째 위치가 가장 먼 곳에서 어디로 이동할 수 있는지 미리 처리한 다음에 접두사와 최적화+스크롤 그룹을 사용하면 된다.
코드
#include
#include
#include
#include
#include
using namespace std;
#define Mod 10007
#define N 50005
int n,m,Max,Min,ans1,ans2;
int a[N],sa[N],last[N],f[2][N],s[2][N];
bool check(int mid)
{
int now,cnt=0;
for (int i=0,j;i<=n;i=j)
{
j=i;now=0;
while (j<=n&&now+a[j]<=mid)
now+=a[j],++j;
++cnt;
}
return cnt<=m+1;
}
int find()
{
int l=Min,r=Max,mid,ans;
while (l<=r)
{
mid=(l+r)>>1;
if (check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
{
scanf("%d",&a[i]);sa[i]=sa[i-1]+a[i];
Max+=a[i],Min=max(Min,a[i]);
}
ans1=find();
int p=0;
for (int i=1;i<=n;++i)
{
while (sa[i]-sa[p]>ans1) ++p;
last[i]=p;
if (!last[i]) f[1][i]=1;
}
for (int i=1;i<=n;++i) s[1][i]=(s[1][i-1]+f[1][i])%Mod;
for (int i=2;i<=m+1;++i)
{
memset(f[i&1],0,sizeof(f[i&1]));
memset(s[i&1],0,sizeof(s[i&1]));
for (int j=i;j<=n;++j)
{
f[i&1][j]=(f[i&1][j]+s[(i-1)&1][j-1])%Mod;
if (last[j]) f[i&1][j]=(f[i&1][j]-s[(i-1)&1][last[j]-1]+Mod)%Mod;
s[i&1][j]=(s[i&1][j-1]+f[i&1][j])%Mod;
}
ans2=(ans2+f[i&1][n]);
}
printf("%d %d
",ans1,(ans2+Mod)%Mod);
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
49일차 - 2022.04.20Baekjoon에서 문제풀이 1) 문제 : 첫째 줄에는 별 1개, 둘째 줄에는 별 2개, N번째 줄에는 별 N개를 찍는 문제/ 첫째 줄에 N(1 ≤ N ≤ 100)이 주어진다. 첫째 줄부터 N번째 줄까지 차례대로 별...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.