肯定是二分+dp
但只能想出n^2m dp
感覺每個數字的狀態都和前面的數字和有關,但劃分是靈活的,可以衍生出多種字首和的情況。
看了題解,但是:
、、 、一臉懵逼,,**是還pascal的、、
自己推(meng)理(bi)了乙個上午,終於推出來了:
第一問是二分裸題、
第二問是字首和優化dp
在對n^2m dp的瘋狂優化之後,終於寫出了兩組遞推式:
f[r]=((qqsum[r-1]-qqsum[l-2])%m+m)%m;
qsum[r]=(qsum[r-1]+f[r])%m;
原理:根據傳統區間dp思想,列舉區間的右端點,但由於隨著右端點的不斷增大,左端點一定是單調向右移的
在(左端點 ~ 右端點-1 )這個區間內都是在<=ans內合法的,左端點往左的就是分出的j-1次的方案數;;
我們只需求出 左端點 ~ 右端點-1 的點往左的上乙個劃分的方案數之和
所以就要用字首和: 右端點的方案數=左端點-1的方案數+左端點的方案數+左端點+1的方案數+左端點+2的方案數+...+右端點-2的方案數+右端點-1的方案數;
=右端點-1的方案數字首和-左端點-2的字首和
大概的流程:
像不像乙隻爬蟲在樹枝上爬?
沒做過這種演算法(其實就沒見過)的題,所以我們是可以利用題目的性質、特點(單調性、邏輯)自己寫出演算法的(甚至有可能創出新的演算法)
演算法競賽的本質就是考驗你的分析能力,並用程式描述你的分析結果
#include#includeusing namespace std;
#define n 50005
#define m 10007
int mid,jishu,a[n],ya,n,m,i,ans1,sum[n],daan,qian[n],qqsum[n],f[n],qsum[n],j,l,r;
bool zai;
int erfen(int l,int r)
}
if(zai)
else r=mid;
} return l;
}int main()
daan+=f[n];
daan%=m;
for(i=1;i<=n;i++)
}printf("%d %d",ans1,daan%m);
}
時間很慢(沒有任何優化,時間應該是 n*3*m的、、)
但bzoj能過,洛谷上過不了,因為時限錯了
%%lych orz orz
木棍分割 HAOI2008
有n根木棍,第i根木棍的長度為li,n根木棍依次鏈結了一起,總共有n 1個連線處.現在允許你最多砍斷m個連 接處,砍完後n根木棍被分成了很多段,要求滿足總長度最大的一段長度最小,並且輸出有多少種砍的方法使得總長 度最大的一段長度最小.並將結果mod 10007。輸入檔案第一行有2個數n,m.接下來n...
HAOI2008 木棍分割
沒寫過幾道的字首和優化 dp 第一問是小學生難度的二分 第二問就直接 dp 了 設 dp i j 表示當前分割點在 i 之後,前面一共分割了 j 段的方案數 利用字首和單調性,通過二分預處理出每乙個點往前能擴充套件到的最大位置,之後字首和優化就可以啦 但是發現這個樣子空間會炸,而這個樣子還沒有辦法滾...
bzoj1044木棍分割
第一問二分答案 第二問dp需優化空間和時間 坑了一天 才寫出個坑爹坑爹程式 program hehe const q 10007 var ans,s,min,max,n,m,i,j,k,l,t longint sum,h array 0.50000 of longint d array 0.5000...