一道非常好的題,太菜了調了很久,細節非常多。
首先,將題意轉化一下,由給定的兩段都有的長度,可以組成多少種組合。
設dp[i]表示,長度為i的方案數。
那麼有轉移,$dp[i] = \sum_^ dp[i-a[j]]$//tot為兩段都有的元素個數,注意要去重
這裡雖然可以用無限數量的揹包思想,但是顯然這樣更好。
然後dp轉移,60分。
//view codeauthor: levil
#includeusing
namespace
std;
typedef
long
long
ll;typedef pair
pii;
const
int n = 1e6+5
;const
int m = 2e5+5
;const ll mod = 1e9+7
;#define rg register
#define pi acos(-1)
#define inf 1e9
#define ct0 cin.tie(0),cout.tie(0)
#define io ios::sync_with_stdio(false)
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace
fastio
while(c >= '
0' && c <= '9')
return x*f;
}void print(int
x)
if(x > 9) print(x/10
); putchar(x%10+'0'
); }
}using
namespace
fastio;
void fre()
int vis[105],a[105],tot = 0
;ll dp[n];
//i拆分的方案數
intmain()
int nf;nf =read();
for(rg int i = 1;i <= nf;++i)
sort(a+1,a+tot+1
);
int len = unique(a+1,a+tot+1)-a-1
; tot =len;
dp[0] = 1
;
for(rg int i = 1;i <= n;++i)
printf(
"%lld\n
",dp[n]);
//system("pause");
}
顯然當n過大時,會超時。而且dp也存不下。
可以發現,塊的大小最多為100,也就是代表一開始最多dp[100]。
那麼我們可以矩陣快速冪加速。
構造初始矩陣f[0] ~ f[99]。那麼右端矩陣即為f[1] ~ f[100]。
那麼可以發現,除了第一行,其他行的轉移矩陣就是1的對角線。即[i][i-1]的位置。
對於第一行 由$f[100] = \sum_^ f[100-a[j]]$
我們可知,對於100-a[j]位置都應該是1,但是由於這裡的橫列相乘後,位置其實是相反的,那麼對於100-a[j]的位置,就變成了a[j]位置,那麼我們對所有a[j]位置都變1即可。
然後矩陣快速冪。應該是n-99次,因為左邊到f[99]。
然後矩陣我們處理出了轉移矩陣的k次,假定為res.
現在初始矩陣為ans.那麼 ans * res 和 res * ans是不一樣的。
這就和我們矩陣乘法的位置有關。//就是這裡調了非常久。
所以最後應該是轉移矩陣 * ans。然後答案就是ans[1][1]。
//view codeauthor: levil
#includeusing
namespace
std;
typedef
long
long
ll;typedef pair
pii;
const
int n = 1e6+5
;const
int m = 2e5+5
;const ll mod = 1e9+7
;#define rg register
#define pi acos(-1)
#define inf 1e9
#define ct0 cin.tie(0),cout.tie(0)
#define io ios::sync_with_stdio(false)
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace
fastio
while(c >= '
0' && c <= '9')
return x*f;
}void print(int
x)
if(x > 9) print(x/10
); putchar(x%10+'0'
); }
}using
namespace
fastio;
void fre()
int a[105],b[105
];struct
mat};
ll f[
105];
mat quick_mi(mat a,ll b)
return
res;
}int
main()
int nf;nf =read();
while(nf--)
mat ans;memset(ans.m,
0,sizeof
(ans.m));
for(rg int i = 1;i <= 100;++i)
for(rg int i = 2;i <= 100;++i) ans.m[i][i-1] = 1
; f[
0] = 1
;
for(rg int i = 1;i < 100;++i)
if(n < 100) printf("
%lld\n
",f[n]);
else
system(
"pause
");
}
洛谷2801 分塊
題目鏈結 題目描述 教主最近學會了一種神奇的魔法,能夠使人長高。於是他準備演示給xmyz資訊組每個英雄看。於是n個英雄們又一次聚集在了一起,這次他們排成了一列,被編號為1 2 n。每個人的身高一開始都是不超過1000的正整數。教主的魔法每次可以把閉區間 l,r 1 l r n 內的英雄的身高全部加上...
洛谷P1471 分塊 方差
傳送門biu 題目大意 給你乙個序列,對其進行區間修改或區間查詢平均數和方差。這他媽是線段樹啊 可是我就是要用分塊艹過你咬我啊 include using namespace std define db double define n 100005 int n,m,bl n t db a n sum...
蒲公英(洛谷4168分塊)
傳送門 若題目是詢問區間是否有過半眾數,就是主席樹,按值域建樹,不斷判斷左右子樹子節點數量大於 r l 1 2,如果一直可以到葉子節點,則return true,否則return false 若題目是詢問區間是否有過半眾數且帶修改,就是樹套樹 雖然我還沒打過樹套樹 那我們可以考慮分塊做法,n 400...