有乙個初始為0的計數器n,每次有兩種操作
①n+1
②把n不含前導0的二進位制接到字串s的末尾
目標是把s變成給出的字串x
求方案數和最小步數
|x|<=5000
設f[i][j]表示放到x的第i位,n為[j,i]的方案,最小值同理
每次列舉上乙個位置轉移,這樣是o(|x|^3)
並且不好判斷二進位制數的大小
按x的所有字尾建trie,把dp丟到樹上去做
設f[i][j]表示當前到trie的節點i,已經放了的長度為j
發現f[i][j]只能從f[j-len[i]]推過來,把前面一維字首和一下可以o(1)轉移
考慮時間複雜度,trie總節點數|x|2,合法dp狀態數|x|2
關於怎麼存最小值:
極限資料100…0,必須加x次,所以不能直接存
設g[i][j]表示到節點i長度j的最小操作1次數,操作2次數可以直接得到
當j=|x|的時候更新答案,同樣只會更新|x|次,每次o(|x|)
總時間還是o(|x|^2)
#include
#define fo(a,b,c) for (register int a=b; a<=c; a++)
#define fd(a,b,c) for (register int a=b; a>=c; a--)
#define min(a,b) (a#define max(a,b) (a>b?a:b)
#define mod 1000000007
#define len 12502500
using
namespace std;
char st[
5002];
struct type ans,a1,a2;
short
int a[len+1]
;int b[len+1]
;int ls[len+1]
;int tr[len+1]
[2];
int a[
5001];
int d[2]
[5001];
int f[
5001];
int g[
5001];
int t[2]
;int i,i2,n,i,j,k,l,sum,len,l,ans;
char ch;
bool bz;
void
add()}
fo(i,a2.len+
1,a1.len)
if(a1.a[i]
>1)
else
break;if
(a1.a[a1.len+1]
)++a1.len;
}else}fo
(i,a1.len+
1,a2.len)
if(a2.a[i]
>1)
else
break;if
(a2.a[a2.len+1]
)++a2.len;}}
void
cmp(
)else
if(ans.a[i]
)return;}
}else
else
if(ans.a[i]
)return;}
}}void
turn
(register
int t)
}int
main()
if(n==
5000)}
a[n+1]
=1;
l=0;
len=1;
fd(i,n,1)
if(a[i])}
}memset
(g,1
,sizeof
(g))
; f[0]
=1; g[0]
=0; ans.len=
2333333
;
i=0;
d[0]
[1]=
1;t[0]
=1; l=-1
;while
(t[i])}
if(tr[d[i]
[i]][0
]) d[i2]
[++t[i2]
]=tr[d[i]
[i]][0
];if(tr[d[i]
[i]][1
]) d[i2]
[++t[i2]
]=tr[d[i]
[i]][1
];}
i=i2;}fd
(i,ans.len,1)
ans=
((ans<<1)
+ans.a[i]
)%mod;
printf
("%d\n"
,f[n]);
printf
("%d\n"
,ans)
;}
JZOJ 雜題選講 友誼
description flowey 是一朵能夠通過友誼顆粒傳播love 的小花 它的友誼顆粒分為兩種,圓粒的和皺粒的,它們依次排列組成了乙個長度為2m 的序列 對於乙個友誼顆 粒的序列,如果存在1 iinput 從friend.in 讀入資料 為一行三個正整數,n,m,p output 輸出到fr...
JZOJ 雜題選講 Bitset Master
換個問題,求每個集合最後的大小。我們發現,如果將 u,v 合併,那麼 f u f v f u f v f u f v 而 f u f v 之和上一次 u,v 合併的結果有關,於是我們可以對每條邊單獨記錄乙個數,表示上一次合併這條邊的結果 回到原問題,我們發現,每個點被哪些集合包含,只需要倒敘處理新問...
2019 2 28 雜題選講
考慮將1至n m分別填入乙個擁有n行m列的 中,不允許重複。你需要滿足以下要求 第i行 1 i n 的最大值為ai。第j列 1 j m 的最大值為bj。請求出合法的填數方案數在模109 7意義下的值。1 n,m 1000 1 ai,bj n m 思路分步 填數 問題符合乘法原理,考慮從大到小填數,先...