1. 程式人生 > >[bzoj1361][Wc2004]孿生項鍊【dp】【字串】【容斥原理】

[bzoj1361][Wc2004]孿生項鍊【dp】【字串】【容斥原理】

fi=2ij|ifj
  那麼答案就是fk/k
  記得要用高精度。
  第一問:我們可以先把給定的串倍長到n,然後在末位+1,進位,並去掉末尾的0,這樣子一定得到比它大的最小串。
  現在我們來證明這是對的,首先最小是肯定的,那麼接下來就是是否迴圈同構了。考慮反證法,如果迴圈同構,那麼後面的那一段在之前一定比前面的小,所以之前的串並不是最小的字典序表示,與給定的事實相反。
  時間複雜度O(K2+N)
【程式碼】
/* - - - - - - - - - - - - - - -
    User :      VanishD
    problem :   [bzoj1361]
    Points :    
- - - - - - - - - - - - - - - */
# include <bits/stdc++.h> # define ll long long # define inf 0x3f3f3f3f # define M 200010 # define N 1010 using namespace std; int read(){ int tmp = 0, fh = 1; char ch = getchar(); while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); } while
(ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); } return tmp * fh; } struct INT{ int len, num[N]; void print(){ for (int i = len; i > 0; i--) printf("%d", num[i]); printf("\n"); } }tnp, f[N], nxt; INT operator -(INT &a, INT &b){ nxt = a; int
i; for (i = 1; i <= nxt.len; i++) nxt.num[i] -= b.num[i]; for (i = 1; i < nxt.len; i++) if (nxt.num[i] < 0) nxt.num[i] += 10, nxt.num[i + 1] -= 1; while (nxt.num[nxt.len] == 0) nxt.len--; return nxt; } INT operator *(INT &a, int b){ nxt = a; int i; for (i = 1; i <= nxt.len; i++) nxt.num[i] *= b; for (i = 1; i <= nxt.len || nxt.num[i] != 0; i++) nxt.num[i + 1] += nxt.num[i] / 10, nxt.num[i] %= 10; nxt.len = i - 1; return nxt; } INT operator /(INT &a, int b){ memset(nxt.num, 0, sizeof(nxt.num)); nxt.len = 0; int i, tmp = 0; for (i = a.len; i >= 1; i--){ tmp = tmp * 10 + a.num[i]; nxt.num[i] = tmp / b; nxt.len = max(nxt.len, (nxt.num[i] > 0) ? i : 0); tmp %= b; } return nxt; } char mp[M]; int n, m, k; int main(){ // freopen("bzoj1361.in", "r", stdin); // freopen("bzoj1361.out", "w", stdout); n = read(), m = read(), k = read(); scanf("\n%s", mp + 1); tnp.len = 1, tnp.num[1] = 1; for (int i = 1; i <= k; i++){ tnp = tnp * 2; f[i] = tnp; for (int j = 1; j < i; j++) if (i % j == 0) f[i] = f[i] - f[j]; } f[k] = f[k] / k; f[k].print(); for (int i = 1; i <= m; i++) mp[i] -= '0'; for (int i = m + 1; i <= n; i++) mp[i] = mp[(i - 1) % m + 1]; mp[n]++; int tmp = n; while (mp[tmp] == 2){ mp[tmp--] = 0; mp[tmp]++; } for (int i = 1; i <= tmp; i++) printf("%d", mp[i]); printf("\n"); return 0; }