今天又考了zjc大爷的原题 然后我惊讶的发现我一道都做不来!!!
真的难受
这道题就是一道在$ac$自动机上面跑得$dp$ 每一次插入一个字符串之后 给他的末尾打上标记
在建立$fail$指针的时候 标记从他的$fail$传递过来 这个标记的作用是表示以这个节点到根节点的串是好的 所以在$dp$的时候应该跳过这个串
方程 $dp[i][son[nd][j]] += dp[i - 1][nd] (! ed[nd])$
代码
#include using namespace std;typedef long long ll;const int N = 6000 + 5;const ll MOD = 12345;int root = 0, son[N][26], cnt, fail[N], m, n;int dp[N][N];bool ed[N];char s[105];queue Q;ll fast_pow(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 insert(int len) { int now = root; for(int i = 0;i < len;i ++) { int nd = s[i] - 'A'; if(! son[now][nd]) son[now][nd] = ++ cnt; now = son[now][nd]; } ed[now] = true;}void build( ) { fail[root] = -1; for(int i = 0;i < 26;i ++) if(son[root][i]) { fail[son[root][i]] = root; Q.push(son[root][i]); } while(! Q.empty( )) { int u = Q.front( ); Q.pop( ); for(int i = 0;i < 26;i ++) { if(son[u][i]) { fail[son[u][i]] = son[fail[u]][i], Q.push(son[u][i]); } else son[u][i] = son[fail[u]][i]; } ed[u] |= ed[fail[u]]; }}void Solve( ) { build( ); for(int i = 1;i <= m;i ++) for(int j = 0;j <= cnt;j ++) { if(ed[j]) continue; for(int k = 0;k < 26;k ++) { dp[i][son[j][k]] = (dp[i][son[j][k]] + dp[i - 1][j]) % MOD; } } ll sum = 0; for(int i = 0;i <= cnt;i ++) if(! ed[i]) sum = (sum + 1ll * dp[m][i]) % MOD; ll ans = fast_pow(1ll * 26, m); ans = ((ans - sum) % MOD + MOD) % MOD; printf("%lld\n", ans);}int main( ) { freopen("text.in","r",stdin); freopen("text.out","w",stdout); scanf("%d%d",& n,& m); for(int i = 1;i <= n;i ++) { scanf("%s", s); int len = strlen(s); insert(len); } dp[0][0] = 1; Solve( );}
本人放弃第二题qwq
这道题是一道双向搜索 把和相同的子集划分成两个集合 一边值取正 另一边取负 那么这个时候他们的和为$0$
为了降低复杂度 我们把所有数分成两个部分 然后一半枚举子集求出他能够到达的所有值的大小
另外一半求出一个大小$sum$之后 在之前求出的一半中找$-sum$ 如果有的话答案就加一 但是这个时候只能保证正负集合分别在这两个部分 但是有可能有元素在正部分中 但是应该属于负数部分的
为了避免这种情况 在枚举的时候就对这个数进行取负的枚举 表示把他分到另外一边集合中
这时候还可能出现子集重复的情况 使用装压避免这种情况(为什么迭代器这么快 我直接$for$就$T$的好惨)
代码
#include #define il inline#define rg registerusing namespace std;typedef long long ll;const int N = 1e7 + 5;const int M = 1e6 + 5;int n, lim, a[M];ll ans;bool vis[N];map
>mp;il int read( ) { int t = 1, ans = 0; char x; x = getchar( ); while(x < '0' || x > '9') { if(x == '-') t = -1; x = getchar( ); } while(x >= '0' && x <= '9') { ans = ans * 10 + x - '0'; x = getchar( ); } return ans * t;}il void Init( ) { n = read( ); lim = n / 2; for(rg int i = 1;i <= n;i ++) a[i] = read( );}il void dfs(int dep, ll sum, int sta) { if(dep == lim + 1) { mp[sum].push_back(sta); return ; } dfs(dep + 1, sum + 1ll * a[dep], sta | (1 << (dep - 1))); dfs(dep + 1, sum - 1ll * a[dep], sta | (1 << (dep - 1))); dfs(dep + 1, sum, sta);}il void get_ans(int dep, ll sum, int sta) { if(dep == n + 1) { if(mp[-sum].size( )) { vector
:: iterator i; vector
:: iterator j; j = mp[-sum].end( ); for(i = mp[-sum].begin( );i != j;i ++) { int now = sta | * i; if(! vis[now]) {vis[now] = true;} } } return ; } get_ans(dep + 1, sum + 1ll * a[dep], sta | (1 << (dep - 1))); get_ans(dep + 1, sum - 1ll * a[dep], sta | (1 << (dep - 1))); get_ans(dep + 1, sum, sta);}il void Solve( ) { dfs(1, 0, 0); get_ans(lim + 1, 0, 0); for(rg int i = 1;i < (1 << n);i ++) ans += vis[i]; printf("%lld\n", ans);}int main( ) { freopen("divide.in","r",stdin); freopen("divide.out","w",stdout); Init( ); Solve( );}
#include using namespace std;typedef long long ll;const int N = 2 * 1e6 + 5;const ll MOD = 1e9 + 7;int T, n, p;ll fac[N], rfac[N];int read( ) { int t = 1, ans = 0; char x; x = getchar( ); while(x < '0' || x > '9') { if(x == '-') t = -1; x = getchar( ); } while(x >= '0' && x <= '9') { ans = ans * 10 + x - '0'; x = getchar( ); } return ans * t;}ll fast_pow(ll a, ll b) { ll ans = 1; for(;b;b >>= 1, a = a * a % MOD) if(b & 1) ans = ans * a % MOD; return ans;}ll C(ll a, ll b) { if(b > a) return 0; return fac[a] * rfac[b] % MOD * rfac[a - b] % MOD;}void Init( ) { scanf("%d",& T); fac[0] = 1; rfac[0] = 1; for(int i = 1;i < N;i ++) fac[i] = fac[i - 1] * i % MOD; rfac[N - 1] = fast_pow(fac[N - 1], MOD - 2); for(int i = N - 2;i >= 1;i --) rfac[i] = rfac[i + 1] * (i + 1) % MOD;}void Solve( ) { while(T --) { n = read( ), p = read( ); ll ans = (1ll * n * p % MOD - 1ll * n * p % MOD * p % MOD + MOD) % MOD; ans = (ans + C(2 * n, n)) % MOD; printf("%lld\n", ans); }}int main( ) { freopen("mathematics.in","r",stdin); freopen("mathematics.out","w",stdout); Init( ); Solve( );}