思路:设前i个句子和+i为sum[i]
dp[i]表示以第i个为结尾的最小不协调度
dp[i]=min(dp[j]+abs(sum[i]-sum[j]-l)^p);
我们发现y=a1+abs(x-b1)^p和y=a2+abs(x-b2)^p至多有一个交点
所以可以用斜率优化
时间复杂度nlogMAXL
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 using namespace std; 6 #define MAXN 110001 7 #define MAXNL 3001000 8 const double INF=1e18; 9 const long long INF2=1000000000000000000LL; 10 int n,l,T,p; 11 double dp[MAXN]; 12 long long dp1[MAXN]; 13 char c[MAXN][31]; 14 int sum[MAXN],Q[MAXN],pre[MAXN],beh[MAXN]; 15 double poww(long double x,int y) 16 { 17 return pow(fabs(x),y); 18 } 19 long long my_pow(int x,int y) 20 { 21 if(x<0) x=-x; 22 long long ans=1; 23 for(int i=1;i<=y;i++) 24 { 25 ans=ans*x; 26 if(ans>INF2) 27 return INF2+1; 28 } 29 return ans; 30 } 31 int search(int x,int y) 32 { 33 int left=-MAXNL,right=MAXNL; 34 while(left<right) 35 { 36 int mid=(left+right)/2; 37 if(dp[x]+poww(mid-sum[x],p)<dp[y]+poww(mid-sum[y],p)) 38 left=mid; 39 else 40 right=mid; 41 if(right-left==1) 42 return left; 43 } 44 } 45 46 bool check(int x,int y,int z) 47 { 48 int num=search(y,z); 49 if(dp[x]+poww(num-sum[x],p)>=dp[y]+poww(num-sum[y],p)) 50 return 0; 51 else return 1; 52 } 53 54 bool solve() 55 { 56 int i; 57 int left,right; 58 left=right=0; 59 Q[0]=0; 60 for(i=1;i<=n;i++) 61 { 62 63 while(left<right&&dp[Q[left]]+poww(sum[i]-l-sum[Q[left]],p)>=dp[Q[left+1]]+poww(sum[i]-l-sum[Q[left+1]],p)) 64 left++; 65 dp[i]=dp[Q[left]]+poww(sum[i]-l-sum[Q[left]],p); 66 dp1[i]=dp1[Q[left]]+my_pow(sum[i]-l-sum[Q[left]],p); 67 pre[i]=Q[left]+1; 68 while(left<right&&check(Q[right-1],Q[right],i)) 69 right--; 70 Q[++right]=i; 71 } 72 if(dp[n]>INF) 73 { 74 printf("Too hard to arrange\n"); 75 return 0; 76 } 77 printf("%lld\n",dp1[n]); 78 return 1; 79 } 80 void output() 81 { 82 int i,j; 83 for(i=n;i>0;i=pre[i]-1) 84 beh[pre[i]]=i; 85 for(i=1;i<=n;i=beh[i]+1) 86 { 87 for(j=i;j<beh[i];j++) 88 printf("%s ",c[j]); 89 printf("%s\n",c[j]); 90 } 91 } 92 93 int main() 94 { 95 scanf("%d",&T); 96 while(T--) 97 { 98 sum[0]=0; 99 scanf("%d%d%d",&n,&l,&p); 100 int i,j; 101 for(i=1;i<=n;i++) 102 { 103 scanf("%s",c[i]); 104 sum[i]=sum[i-1]+strlen(c[i])+1; 105 }; 106 l++; 107 dp1[0]=0; 108 dp[0]=0; 109 solve(); 110 output(); 111 printf("--------------------\n"); 112 } 113 return 0; 114 }