題目連接ios
輸出$n$個$n$便可。c++
<details> <summary>Code</summary>git
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main() { ios::sync_with_stdio(false); cin.tie(0); int T; cin >> T; while(T--) { int n; cin >> n; } return 0; }
</details>算法
十進制快速冪,$a^n=(a^2)^{\frac{n}{2}}$改造爲$a^n=(a^{10})^(\frac{n}{10})$便可,餘數就單獨乘一下。 詳見代碼:數組
<details> <summary>Code</summary>網絡
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 3, MAX = 1e6 + 15; ll a, b, x0, x1, MOD; char s[MAX]; struct matrix{ int A[N][N]; int n,m; matrix(){memset(A,0,sizeof(A));} }; int add(ll x, ll y) { x += y; if(x >= MOD) x -= MOD; return x; } int mul(ll x, ll y) { return (x *= y) >= MOD ? x % MOD : x; } matrix operator * (const matrix &a,const matrix &b){ matrix ans; ans.n=a.n;ans.m=b.m; for(int i=1;i<=ans.n;i++) for(int j=1;j<=ans.m;j++) for(int k=1;k<=b.n;k++) ans.A[i][j] = add(ans.A[i][j], mul(a.A[i][k], b.A[k][j])) ; return ans ; } matrix operator + (const matrix &a,const matrix &b){ matrix ans; ans.n=a.n;ans.m=a.m; for(int i=1;i<=ans.n;i++){ for(int j=1;j<=ans.m;j++){ ans.A[i][j]=(a.A[i][j]+b.A[i][j])%MOD; } } return ans ; } matrix qp_Mat(matrix a,ll b){ matrix ans; ans.n=ans.m=a.n; for(int i=1;i<=ans.n;i++) ans.A[i][i]=1; while(b){ if(b&1) ans=ans*a; a=a*a; b>>=1; } return ans ; } int main() { scanf("%lld%lld%lld%lld", &x0, &x1, &a, &b); scanf("%s", s); scanf("%lld", &MOD); matrix trans; trans.n = trans.m = 2; trans.A[2][1] = 1; trans.A[1][2] = b; trans.A[2][2] = a; matrix ans; ans.n = ans.m = 2; ans.A[1][1] = ans.A[2][2] = 1; int last = strlen(s) - 1; while(last >= 0) { if(s[last] != '0') { int now = s[last] - '0'; ans = ans * qp_Mat(trans, now); } trans = qp_Mat(trans, 10); last--; } matrix A; A.n = 1, A.m = 2; A.A[1][1] = x0, A.A[1][2] = x1; A = A * ans; cout << A.A[1][1] << endl; return 0; }
</details>dom
BSGS算法,對於題目給出的$x_i=ax_{i-1}+b\mod p$,求其通項爲:$x_n=a^nx_0+\frac{b(1-a^n)}{1-a}$,由於題目要求$x_i=v\mod p$,咱們將全部與$a_n$無關的放在等式右邊,獲得:$a^n=\frac{v+\frac{b}{a-1}}{x_0+\frac{b}{a-1}}\mod p$。 根據BSGS,咱們會扔一個$a^j$到右邊去,每次預處理右邊部分,放在哈希表裏面,對於左邊直接枚舉進行查找。在這個題中由於詢問次數較多,直接這樣很容易T。 因此能夠考慮將預處理提出去,那麼咱們將$n$寫爲$it+j,t=\lceil\sqrt(p)\rceil$的形式,而後把$a^{it}$的逆元乘在右邊,在詢問前預處理左邊的,這樣就會快不少。 這裏有個迷的地方就是我將$n$處理爲$it-j$的形式時一直卡在96...$i*t+j$就過了。。。不知道什麼狀況。 代碼以下:ui
<details> <summary>Code</summary>spa
#include <bits/stdc++.h> using namespace std; typedef long long ll; struct B{ const int mod = 524287; // (1 << 19) - 1; int tot; int h[524288], next[524288], L[524288], v[524288]; int Find(ll x) { int k = h[x & mod]; while(k != 0) { if(L[k] == x) return v[k]; else k = next[k]; } return -1; } void Add(int e, int i) { tot++; next[tot] = h[e & mod]; L[tot] = e; v[tot] = i; h[e & mod] = tot; } void init(int a, int n) { memset(h, 0, sizeof(h)); memset(L, 0, sizeof(L));tot = 0; memset(next, 0, sizeof(next)); memset(v, 0, sizeof(v)); ll t, e = 1; t = (int)sqrt(n) + 1; for(int i = 0; i < t; i++) { if(Find(e) == -1) Add(e, i); e = e * a % n; } } ll BSGS(int a, int b, int n, ll v, ll t) { // a ^ x = b (mod n) for(int i = 0; i < t; i++) { if(Find(b) != -1) return i * t + Find(b); b = b * v % n; } return -1; } }S; int p; ll qp(ll a, ll b) { ll ans = 1; while(b) { if(b & 1) ans = ans * a % p; a = a * a % p; b >>= 1; } return ans; } ll n; int x0, a, b, T, q; int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> T; while(T--) { cin >> n >> x0 >> a >> b >> p; if(a == 0) { cin >> q; while(q--) { int v; cin >> v; if(x0 == v) cout << 0 << '\n'; else if(b == v) cout << 1 << '\n'; else cout << -1 << '\n'; } continue; } if(a == 1) { cin >> q; ll tmp = qp(b, p - 2); while(q--) { int v; cin >> v; int ans = 1ll * (v - x0 + p) % p * tmp % p; if(ans >= n) cout << -1 << '\n'; else cout << ans << '\n'; } continue; } int c = 1ll * b * qp(a - 1, p - 2) % p; int t = (int)sqrt(p) + 1; S.init(a, p); cin >> q; while(q--) { int v; cin >> v; ll x = v + c, y = x0 + c; if(y % p == 0) { if(x % p == 0) cout << 0 << '\n'; else cout << -1 << '\n'; continue ; } ll z = x * qp(y, p - 2) % p; int k = qp(qp(a, t), p - 2); ll ans = S.BSGS(a, z, p, k, t); if(ans == -1 || ans >= n) cout << -1 << '\n'; else cout << ans << '\n'; } } return 0; }
</details>code
狀壓$dp$+揹包,由於題目求的是子集。注意空間限制,因此$dp$數組用char類型。 代碼以下:
<details> <summary>Code</summary>
#include <bits/stdc++.h> using namespace std; const int N = 26; char dp[1 << N]; int e[N]; int n, m; int Max(char x, char y) { return x > y ? x : y; } int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> m; for(int i = 1; i <= m; i++) { int u, v; cin >> u >> v; e[u] |= (1 << v); e[v] |= (1 << u); } for(int i = 0; i < n; i++) { e[i] ^= (1 << i); e[i] = ~e[i]; } int ans = 0; for(int i = 1; i < (1 << n); i++) { int lb = __builtin_ffs(i) - 1; dp[i] = Max(dp[i ^ (1 << lb)], dp[i & e[lb]] + 1); ans += dp[i]; } cout << ans; return 0; }
</details>
題目要求最大團,將問題轉換一下,考慮求最大獨立集。 最大團是任意兩點之間$bit$相差超過1,那麼其補圖就是任意兩點之間$bit$之差等於1了(任意兩個數都不相等)。對其補圖建出來很容易發現其爲二分圖。假設左邊全是$bit$個數爲奇數的點,那麼右邊就是$bit$個數爲偶數的點,而後跑個網絡流就好了。 輸出方案的時候注意,這裏利用的是增光時候的最後一次bfs,而後手玩一下bfs過程,就知道爲啥這樣輸出了,本質和從二分圖左邊未標記點dfs的方法是同樣的:都是從左邊未標記點開始,而後訪問右邊標記點,bfs再利用反邊不斷標記左邊的點,就一直重複。。。因此最後左邊未標記的點和右邊標記的點就是最小點覆蓋的答案,最大獨立集把這些點去掉就行。 代碼以下:
<details> <summary>Code</summary>
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 5005; int n; int a[N]; #define INF 0x3f3f3f3f template <class T> struct Dinic{ struct Edge{ int v, next; T flow; Edge(){} Edge(int v, int next, T flow) : v(v), next(next), flow(flow) {} }e[5 * 1000000]; int head[N], cur[N], tot; int dep[N]; void init() { memset(head, -1, sizeof(head)); tot = 0; } void adde(int u, int v, T w, T rw = 0) { e[tot] = Edge(v, head[u], w); head[u] = tot++; e[tot] = Edge(u, head[v], rw); head[v] = tot++; } bool BFS(int _S, int _T) { memset(dep, -1, sizeof(dep)); queue <int> q; q.push(_S); dep[_S] = 0; while(!q.empty()) { int u = q.front(); q.pop(); for(int i = head[u]; ~i; i = e[i].next) { int v = e[i].v; if(dep[v] == -1 && e[i].flow > 0) { dep[v] = dep[u] + 1; q.push(v); } } } return dep[_T] != -1; } T dfs(int _S, int _T, T a) { T flow = 0, f; if(_S == _T || a == 0) return a; for(int i = head[_S]; ~i; i = e[i].next) { int v = e[i].v; if(dep[v] != dep[_S] + 1) continue; f = dfs(v, _T, min(a, e[i].flow)); if(f) { e[i].flow -= f; e[i ^ 1].flow += f; flow += f; a -= f; if(a == 0) break; } } if(!flow) dep[_S] = -1; return flow; } T dinic(int _S, int _T) { T max_flow = 0; while(BFS(_S, _T)) { max_flow += dfs(_S, _T, INF); } return max_flow; } }; bool is_source[N]; Dinic <int> D; bool ok(int x) { return x && ((x & (x - 1)) == 0); } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); if(__builtin_popcount(a[i]) & 1) is_source[i] = 1; } D.init(); for(int i = 1; i <= n; i++) { if(is_source[i]) D.adde(0, i, 1); else D.adde(i, n + 1, 1); } for(int i = 1; i <= n; i++) { for(int j = i + 1; j <= n; j++) { if(ok(a[i] ^ a[j])) { if(is_source[i]) D.adde(i, j, 1); else D.adde(j, i, 1); } } } int ans = n - D.dinic(0, n + 1); printf("%d\n", ans); vector <int> res; for(int i = 1; i <= n; i++) { if(is_source[i]) { if(D.dep[i] != -1) res.push_back(a[i]); } else { if(D.dep[i] == -1) res.push_back(a[i]); } } int SZ = res.size(); for(int i = 0; i < SZ; i++) { printf("%d%c", res[i], " \n"[i == SZ - 1]); } return 0; }
</details>
一個數要大於另一個數,要麼其位數大於它,要麼長度相等時某一位大於它。那麼根據這個來搞就行。 位數大於的狀況比較好處理,就是一個組合數的問題:枚舉起點而後在後面選若干個(由於不能有前導零)。 等於的狀況先$dp$匹配出相等的方案數,設$dp(i,j)$表示第一個串到了$i$位,選出來了$j$個可以和第二個串前$j$位相等的方案數。而後根據下一位之間的大小關係進行轉移和計算。
<details> <summary>Code</summary>
#include<bits/stdc++.h> typedef long long ll; const int MAXN = 3e3 + 5, N = 3e3, MAXM = 3e5 + 5, INF = 0x3f3f3f3f, MOD = 998244353; const ll INFL = 0x3f3f3f3f3f3f3f3f; using namespace std; const int oo = (1e9) - (1e6); #define lson o<<1,l,m #define rson o<<1|1,m+1,r #define mid l + ((r-l)>>1) #define pb push_back #define RR register #define random(a,b) ((a)+rand()%((b)-(a)+1)) #define all(v) (v.begin(),v.end()) #define lc(x) c[x][0] #define rc(x) c[x][1] #define R register int typedef long double db; typedef unsigned int uint; #define G c=getchar() int t, n, m, dp[MAXN][MAXN]; char s1[MAXN], s2[MAXN]; ll fact[MAXN], ifact[MAXN], sum[MAXN][MAXN]; inline void add(int &x, int y) { x += y; if (x >= MOD)x -= MOD; } inline ll C(int n, int m) { if (m > n)return 0; return fact[n] * ifact[n - m] % MOD*ifact[m] % MOD; } ll qpow(ll a, ll b) { ll ans = 1; for (; b; b >>= 1, a = a * a%MOD)if (b & 1)ans = ans * a%MOD; return ans; } void init() { fact[0] = fact[1] = 1; for (int i = 2; i <= N; i++)fact[i] = fact[i - 1] * i%MOD; ifact[N] = qpow(fact[N], MOD - 2); for (int i = N - 1; i >= 0; i--)ifact[i] = ifact[i + 1] * (i + 1) % MOD; for (int i = 1; i <= N; i++) { sum[i][0] = 1; for (int j = 1; j <= i; j++) { sum[i][j] = (sum[i][j - 1] + C(i, j)) % MOD; assert(sum[i][j] >= 0); } } } int main() { ios::sync_with_stdio(false); cin.tie(0); init(); cin >> t; while (t--) { cin >> n >> m; cin >> (s1 + 1) >> (s2 + 1); for (int i = 0; i <= n; i++) for (int j = 0; j <= n; j++)dp[i][j] = 0; dp[0][0] = 1; for (int i = 1; i <= n; i++) { dp[i][0] = 1; for (int j = 1; j <= min(i, m); j++) { dp[i][j] = dp[i - 1][j]; if (s2[j] != s1[i])continue; add(dp[i][j], dp[i - 1][j - 1]); } } int ans = 0; for (int i = 1; i <= n; i++) { if (s1[i] != '0' && n - i >= m) { add(ans, (sum[n - i][n - i] - sum[n - i][m - 1] + MOD) % MOD); } for (int j = 1; j <= min(i, m); j++) { if (s1[i] <= s2[j])continue; add(ans, dp[i - 1][j - 1] * C(n - i, m - j) % MOD); } } cout << ans << '\n'; } return 0; }
</details>
由於知道兩兩之間的大小關係,最後要肯定一個大小關係,因此能夠想到拓撲序來搞。 主要就是注意一下代碼的細節就是了。
<details> <summary>Code</summary>
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e4 + 5, M = 1e6 + 5; int n, m, cnt; vector <int> g[26]; string str; struct Edge { int v, next; }e[M << 1]; int head[N], tot; char mp[N], ans[N]; void adde(int u, int v) { e[tot].v = v; e[tot].next = head[u]; head[u] = tot++; } int in[N], num[26]; int main() { scanf("%d%d", &n, &m); memset(num, -1, sizeof(num)); memset(head, -1, sizeof(head)); int flag = 0; for (int i = 1; i <= m * (m - 1) / 2; i++) { char s[10]; scanf("%s", s); int len; scanf("%d", &len); getchar(); getline(cin, str); if (cnt > n) { //以前沒這個一直RE flag = 1; continue; } int cnt1 = 0, cnt2 = 0; for (int j = 0; j < len; j++) { if (str[j] == s[0]) cnt1++; else cnt2++; } int t1 = s[0] - 'a', t2 = s[1] - 'a'; if (num[t1] == -1) { num[t1] = cnt1; while (cnt1--) g[t1].push_back(++cnt), mp[cnt] = s[0]; } else { if (num[t1] != cnt1) flag = 1; } if (num[t2] == -1) { num[t2] = cnt2; while (cnt2--) g[t2].push_back(++cnt), mp[cnt] = s[1]; } else { if (num[t2] != cnt2) flag = 1; } if (flag) continue; int p1 = 0, p2 = 0; for (int j = 0; j < len - 1; j++) { if (str[j] == s[0]) { if (str[j + 1] == s[0]) { adde(g[t1][p1], g[t1][p1 + 1]); in[g[t1][p1 + 1]]++; } else { adde(g[t1][p1], g[t2][p2]); in[g[t2][p2]]++; } p1++; } else { if (str[j + 1] == s[0]) { adde(g[t2][p2], g[t1][p1]); in[g[t1][p1]]++; } else { adde(g[t2][p2], g[t2][p2 + 1]); in[g[t2][p2 + 1]]++; } p2++; } } } if (cnt != n || flag) { cout << -1; return 0; } int tmp = 0; queue <int > q; for (int i = 1; i <= cnt; i++) if (!in[i]) q.push(i); while (!q.empty()) { if ((int)q.size() > 1) { //嚴格拓撲序,那麼隊列中只有一個 cout << -1; return 0; } int u = q.front(); q.pop(); ans[++tmp] = mp[u]; int k = 0; for (int i = head[u]; i != -1; i = e[i].next) { int v = e[i].v; if (--in[v] == 0) q.push(v), k++; } } if (tmp != n) { cout << -1; return 0; } for (int i = 1; i <= tmp; i++) cout << ans[i]; return 0; }
</details>