2312-Magical Girl Sayaka-chan
解法
まず,円ではなく直線上に並べること考えると,音符を音程でソートするのが最適になる.
円の場合は下の図のように,2つの直線に分けて考えることが出来る.
よって,音符を2つの直線に割り振る問題となる.
ゆえにdp[1本目の最後の音符番号][2本目の最後の音符番号]とすることで,
O(N^2)で計算できる.
実装(C++)
#include <algorithm> #include <vector> #include <iostream> #include <cstring> #include <cstdio> using namespace std; typedef long long int lli; #define REP(i,x) for(int i=0;i<(int)(x);i++) lli N,M,L; lli S[110000]; lli K[110000]; lli sum[110001]; //累積和 lli dp[2200][2200]; inline lli calc(int a,int b){ return (sum[b+1]-sum[a])/L; } lli solve(int back1,int back2){ if(back1<back2)swap(back1,back2); if(dp[back1][back2]>=0)return dp[back1][back2]; int now=max(back1,back2); if(now==N-1){ return dp[back1][back2]=calc(K[min(back1,back2)],K[now]); } lli res=min(solve(now+1,back2)+calc(K[back1],K[now+1]),solve(back1,now+1)+calc(K[back2],K[now+1])); return dp[back1][back2]=res; } lli readint(){ int t; scanf("%d",&t); return t; } int main(){ N=readint(); M=readint(); L=readint(); memset(dp,-1,sizeof(dp)); REP(i,N){ K[i]=readint(); K[i]--; } std::sort(K,K+N); REP(i,M){ S[i]=readint(); } sum[0]=0; for(int i=1;i<=M;i++){ sum[i]=sum[i-1]+S[i-1]; } cout<<solve(0,0)<<endl; }