您现在的位置是:主页 > news > 潍坊网站制作小程序/武汉网站推广公司

潍坊网站制作小程序/武汉网站推广公司

admin2025/5/1 3:22:18news

简介潍坊网站制作小程序,武汉网站推广公司,企业邮箱域名怎么设置,如何不让百度收录网站ProblemSet 签到题就不写了。 C. Distinct Substrings 先对原串建出SAM,map存边。 由于这题相当于添加一个字符再删除这个字符,添加下一个字符,所以每次都暴力跳后缀链接是复杂度是错的。 从 \(last\) 向上跳的时候,遍历出边&…

潍坊网站制作小程序,武汉网站推广公司,企业邮箱域名怎么设置,如何不让百度收录网站ProblemSet 签到题就不写了。 C. Distinct Substrings 先对原串建出SAM,map存边。 由于这题相当于添加一个字符再删除这个字符,添加下一个字符,所以每次都暴力跳后缀链接是复杂度是错的。 从 \(last\) 向上跳的时候,遍历出边&…

ProblemSet

签到题就不写了。

C. Distinct Substrings

先对原串建出SAM,map存边。

由于这题相当于添加一个字符再删除这个字符,添加下一个字符,所以每次都暴力跳后缀链接是复杂度是错的。

\(last\) 向上跳的时候,遍历出边,把每个拥有数字 \(c\) 的出边的第一个点编号记下来,由于后缀自动机的边数是线性的,这样复杂度就是对的 \(O(n\log n)\) 虽然 \(5e6\) 但数据水还是跑过去了。

#include <iostream>
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <fstream>typedef long long LL;
typedef unsigned long long uLL;#define Int __int128
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define MP(x, y) std::make_pair(x, y)
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define GO cerr << "GO" << endl;using namespace std;inline void proc_status()
{ifstream t("/proc/self/status");cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;
}template<class T> inline T read() 
{register int x = 0; register int f = 1; register char c;while (!isdigit(c = getchar())) if (c == '-') f = -1;while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar()));return x * f;
}template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }const int maxN = (int) 1e6;
const int mod = (int) 1e9 + 7;int pw[maxN + 2];
int ncnt, last, n, m;struct Status
{int len, link;map<int, int> ch;
} st[2 * maxN];void init() { ncnt = 0, last = 0, st[0].len = 0, st[0].link = -1; }void insert(int c)
{int cur = ++ncnt;int p = last;st[cur].len = st[last].len + 1;while (p != -1 and !st[p].ch.count(c)){st[p].ch[c] = cur;p = st[p].link;}if (p == -1)st[cur].link = 0;else{int q = st[p].ch[c];if (st[q].len == st[p].len + 1)st[cur].link = q;else {int clone = ++ncnt;st[clone] = st[q];st[clone].len = st[p].len + 1;while (p != -1 and st[p].ch[c] == q){st[p].ch[c] = clone;p = st[p].link;}st[cur].link = st[q].link = clone;}}last = cur;
}void Clear()
{for (register int i = 0; i <= ncnt; ++i) st[i].ch.clear(), st[i].len = st[i].link = 0;ncnt = last = 0;
}void Init() 
{pw[0] = 1;for (register int i = 1; i <= m; ++i) pw[i] = 3ll * pw[i - 1] % mod;
}void Solve()
{int ans = 0;static int place[maxN + 2];fill(place + 1, place + 1 + m, -1);int L = st[last].len + 1, p = last;while (p != -1){for (map<int, int>::iterator it = st[p].ch.begin(); it != st[p].ch.end(); ++it){if (place[it->first] < 0)place[it->first] = p;}p = st[p].link;}for (register int i = 1; i <= m; ++i){if (place[i] == -1)ans ^= (LL) L * pw[i] % mod;else ans ^= (LL) (L - st[place[i]].len - 1) * pw[i] % mod;}cout << ans << endl;
}int main() 
{
#ifndef ONLINE_JUDGEfreopen("C.in", "r", stdin);freopen("C.out", "w", stdout);
#endifwhile (scanf("%d%d", &n, &m) != EOF){init();Init();for (register int i = 1, x; i <= n; ++i) x = read<int>(), insert(x);Solve();Clear();}return 0;
}

D. Modulo Nine

\(dp[i][j][k]\) 表示填了前 \(i\) 个位置,最近的一个含3这个因子的数在 \(k\),次近的在 \(j\)的方案数。

那么对每个点求出一个最近的需要满足限制的左端点(没有就默认为0),如果状态 \(dp[i][j][k]\) 满足 j和k都在i最近的左端点内,那么这个状态就是合法的,接下考虑i+1位填 \(\{0, 9\}\)\(\{3, 6\}\)\(\{1, 2, 4, 5, 7, 8\}\),刷表转移即可。

Code

#include <iostream>
#include <cstring>
#include <cstdio>using namespace std;void chkmax(int &x, int y) { x < y ? x = y : 0; }const int maxN = 50;
const int mod = (int) 1e9 + 7;int n, m;
int L[maxN + 2];
int dp[maxN + 2][maxN + 2][maxN + 2];void pls(int &x, int y) 
{x += y;if (x >= mod) x -= mod;if (x < 0) x += mod;
}int main()
{freopen("D.in", "r", stdin);freopen("D.out", "w", stdout);while (scanf("%d%d", &n, &m) != EOF){memset(L, 0, sizeof L);for (int i = 1; i <= m; ++i){int l, r;scanf("%d%d", &l, &r);chkmax(L[r], l);}memset(dp, 0, sizeof dp);dp[0][0][0] = 1;for (int i = 0; i < n; ++i)for (int j = 0; j <= i; ++j)for (int k = j; k <= i; ++k){if (!dp[i][j][k]) continue;if (L[i] <= j and L[i] <= k){int curr = dp[i][j][k];// {1, 2, 4, 5, 7, 8}pls(dp[i + 1][j][k], 6ll * curr % mod); // {3, 6}pls(dp[i + 1][k][i + 1], 2ll * curr % mod);// {0, 9}pls(dp[i + 1][i + 1][i + 1], 2ll * curr % mod);}}int ans = 0;for (int i = L[n]; i <= n; ++i)for (int j = i; j <= n; ++j)pls(ans, dp[n][i][j]);printf("%d\n", ans);}
}

G. 字典序

参考了zsy的题解:

不难发现只要考虑相邻两行的限制,如果满足任意相邻两行满足,那么就是合法的,即 \(\forall i\in[1, n - 1],j\in[2,m],\exists k < j\) 满足 \(a[i][j] > a[i + 1][j]\)\(a[i][k] < a[i + 1][k]\)

这个限制可以抽象成 \(1\le i\le n - 1\)\(\{1,2\cdots m\}\) 的两个子集 \(A[i]\)\(B[i]\),需要满足最终的排列中 \(B[i]\) 中的每一个元素都在至少一个 \(A[i]\) 中元素的后面。

那么每个点(列)会有些限制,这些限制的个数就是被多少个B集合包含,因为B集合是被A集合限制的,当限制个数为0时,我们就可以把它加入到排列中了。

4 3 3
1 5 1
1 5 1
3 5 2

比如上面这个:\(A[1] = \{2\},A[2] = \{\}, A[3]=\{1,3\}\), \(B[1] = \{1, 3\}, B[2] = \{\}, B[3] = \{\}\)

我们从前往后构造排列,若构造了 \(A[x]\) 中的数,那么对应的 \(B[x]\) 所包含的列的限制就会-1,所以每次找到最小的限制数为0的列,作为当前构造排列的最后一个,然后把它所在 \(A[x]\) 集合对应的 \(B[x]\) 集合中的列的限制-1,再将 \(A[x]\)\(B[x]\) 删掉。

Code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>using namespace std;const int maxN = 2000;int n, m, a[maxN + 2][maxN + 2];
int limits[maxN + 2];
vector<int> B_to_Lie[maxN + 2];
vector<int> Lie_to_A[maxN + 2];int main()
{freopen("G.in", "r", stdin);freopen("G.out", "w", stdout);while (scanf("%d%d", &n, &m) != EOF){memset(limits, 0, sizeof limits);for (int i = 1; i < n; ++i) B_to_Lie[i].clear();for (int i = 1; i <= m; ++i) Lie_to_A[i].clear();for (int i = 1; i <= n; ++i)for (int j = 1; j <= m; ++j)scanf("%d", &a[i][j]);for (int i = 1; i < n; ++i)for (int j = 1; j <= m; ++j)if (a[i][j] < a[i + 1][j])Lie_to_A[j].push_back(i);else if (a[i][j] > a[i + 1][j]){limits[j]++;B_to_Lie[i].push_back(j);}int tot = 0;static int ans[maxN + 2];for (int t = 1; t <= m; ++t){int p = 0;for (int i = 1; i <= m; ++i)if (!limits[i]){p = i;limits[i] = 0x3f3f3f3f;break;}if (!p)break;ans[++tot] = p;for (int i = 0; i < (int) Lie_to_A[p].size(); ++i){int A = Lie_to_A[p][i];for (int j = 0; j < (int) B_to_Lie[A].size(); ++j){int Lie = B_to_Lie[A][j];limits[Lie]--;}B_to_Lie[A].clear();}Lie_to_A[p].clear();}if (tot == m)for (int i = 1; i <= m; ++i)if (i != m) printf("%d ", ans[i]);else printf("%d\n", ans[i]);else puts("-1");}return 0;
}

H. 有向图

\(E[u]\) 为走无限次后期望经过 \(u\) 多少次,由于经过n+1...n+m的次数为1,所以此时n+1...n+m点期望就是概率。

列出方程高消即可。

Code

#include <iostream>
#include <cstring>
#include <cstdio>#define LL long longusing namespace std;const int maxN = 500;
const int mod = (int) 1e9 + 7;LL qpow(LL a, LL b)
{LL ans = 1;while (b) {if (b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;
}int n, m;
int a[maxN + 2][maxN + 2], P[maxN + 2][maxN + 2];int main()
{freopen("H.in", "r", stdin);freopen("H.out", "w", stdout);while (scanf("%d%d", &n, &m) != EOF){memset(a, 0, sizeof a);memset(P, 0, sizeof P);int inv = qpow(10000, mod - 2);for (int i = 1; i <= n; ++i)for (int j = 1; j <= n + m; ++j){scanf("%d", &P[i][j]);P[i][j] = 1ll * P[i][j] * inv % mod;}for (int i = 1; i <= n; ++i){for (int j = 1; j <= n; ++j){a[i][j] = P[j][i];if (i == j) a[i][i]--;(a[i][j] += mod) %= mod;}if (i == 1) a[1][n + 1] = mod - 1;else a[i][n + 1] = 0;}for (int i = 1; i <= n; ++i){for (int j = 1; j <= n; ++j)if (i != j){int mul = 1ll * a[j][i] * qpow(a[i][i], mod - 2) % mod;for (int k = 1; k <= n + 1; ++k){a[j][k] -= 1ll * a[i][k] * mul % mod;a[j][k] %= mod;(a[j][k] += mod) %= mod;}}}for (int i = 1; i <= n; ++i)a[i][n + 1] = (1ll * a[i][n + 1] * qpow(a[i][i], mod - 2) % mod + mod) % mod;for (int i = 1 + n; i <= n + m; ++i){int ans = 0;for (int j = 1; j <= n; ++j)(ans += 1ll * a[j][n + 1] * P[j][i] % mod) %= mod;printf("%d", (ans + mod) % mod);if (i != n + m) putchar(' ');}putchar('\n');}
}

J. Parity of Tuples (Easy)

首先对每一行单独考虑贡献再加起来。

接下来都是对一行考虑:

由于要求and x后二进制下都是奇数个1,所以设 \(f[i][S]\) 为考虑了 \(x\) 的前i位,这一行每个数二进制下1个数的奇偶性二进制状态为S对答案的贡献。

对于 \(3^x\) 将x拆成二进制相加,转移时乘上即可。

Code

#include <iostream>
#include <cstdio>
#include <cstring>using namespace std;const int maxN = (int) 1e4, maxM = 30, maxK = 30;
const int mod = (int) 1e9 + 7;int n, m, k;
int b[maxK + 2], pw[maxK + 2];
int a[maxN + 2][maxM + 2];
int f[maxK + 2][1 << maxM];int main()
{freopen("J.in", "r", stdin);freopen("J.out", "w", stdout);while (scanf("%d%d%d", &n, &m, &k) != EOF){for (int i = 1; i <= n; ++i)for (int j = 0; j < m; ++j)scanf("%d", &a[i][j]);int ans = 0;for (int t = 1; t <= n; ++t){for (int i = 0; i <= k; ++i){b[i] = 0;for (int j = 0; j < m; ++j)b[i] |= (a[t][j] >> i & 1) << j;}pw[0] = 3;for (int i = 1; i <= k; ++i)pw[i] = 1ll * pw[i - 1] * pw[i - 1] % mod;memset(f, 0, sizeof f);f[0][0] = 1;for (int i = 0; i < k; ++i)for (int S = 0; S < (1 << m); ++S)if (f[i][S]){(f[i + 1][S ^ b[i]] += 1ll * f[i][S] * pw[i]) %= mod;(f[i + 1][S] += f[i][S]) %= mod;}(ans += f[k][(1 << m) - 1]) %= mod;}printf("%d\n", (ans + mod) % mod);}
}

K. 双向链表练习题

deque 启发式合并。

Code

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <fstream>typedef long long LL;
typedef unsigned long long uLL;#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define MP(x, y) std::make_pair(x, y)
#define DE(x) cerr << x << endl;
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define GO cerr << "GO" << endl;
#define rep(i, a, b) for (register int (i) = (a); (i) <= (b); ++(i))using namespace std;inline void proc_status()
{ifstream t("/proc/self/status");cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;
}
inline int read() 
{register int x = 0; register int f = 1; register char c;while (!isdigit(c = getchar())) if (c == '-') f = -1;while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar()));return x * f;
}
template<class T> inline void write(T x) 
{static char stk[30]; static int top = 0;if (x < 0) { x = -x, putchar('-'); }while (stk[++top] = x % 10 xor 48, x /= 10, x);while (putchar(stk[top--]), top);
}
template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }const int maxN = 2e5;deque<int> q[maxN + 2];
int n, m;
bool rev[maxN + 2];int size(int x) { return q[x].size(); }int front(int x)
{if (rev[x]) return q[x].back();else return q[x].front();
}int back(int x)
{if (rev[x]) return q[x].front();else return q[x].back();
}void push_front(int x, int y)
{if (rev[x]) q[x].push_back(y);else q[x].push_front(y);
}void push_back(int x, int y)
{if (rev[x]) q[x].push_front(y);else q[x].push_back(y);
}void pop_back(int x)
{if (rev[x]) q[x].pop_front();else q[x].pop_back();
}void pop_front(int x)
{if (rev[x]) q[x].pop_back();else q[x].pop_front();
}int main() 
{
#ifndef ONLINE_JUDGEfreopen("K.in", "r", stdin);freopen("K.out", "w", stdout);
#endifwhile (scanf("%d%d", &n, &m) != EOF){for (int i = 1; i <= n; ++i)q[i].clear(), q[i].push_front(i), rev[i] = 0;for (int i = 1; i <= m; ++i){int a, b;scanf("%d%d", &a, &b);if (q[a].size() > q[b].size()){while (size(b)){push_back(a, front(b));pop_front(b);}rev[a] ^= 1;} else {while (size(a)){push_front(b, back(a));pop_back(a);}rev[a] = rev[b] ^ 1;swap(q[a], q[b]);}}printf("%d", q[1].size());if (rev[1]) { while (q[1].size()) printf(" %d", q[1].back()), q[1].pop_back(); }else { while (q[1].size()) printf(" %d", q[1].front()), q[1].pop_front(); }puts("");}return 0;
}

转载于:https://www.cnblogs.com/cnyali-Tea/p/11443455.html