湖南省队集训 Day 2
暴力分又没骗满sad.....
Problem A 走路
$O(n^2)$动态规划是显然的。
更新方式有两种:一种是枚举它的倍数转移,一种是转移到它的约数。
考虑利用分块来平衡一下(像分块FWT一样)。
注意到若$x = ab, y = cd, (a, b) = 1, (c, d) = 1$,那么$x | y$的充分必要条件是$a | c, b | d$或者$a | d, b | c$。
那么我们可以把$v_1$拆成$AB, (A, B) = 1$,使得$A$和$B$的约数个数尽量相等。
对于每一部分,离散化后暴力处理整除关系。每次修改或查询时固定一维动另一维。
时间复杂度$O(nV^{0.25})$。
Code
1 #include <algorithm> 2 #include <iostream> 3 #include <cassert> 4 #include <cstdlib> 5 #include <cstdio> 6 #include <vector> 7 #include <ctime> 8 #ifndef WIN32 9 #define Auto "%lld" 10 #else 11 #define Auto "%I64d" 12 #endif 13 using namespace std; 14 typedef bool boolean; 15 16 #define ll long long 17 #define ull unsigned long long 18 19 template <typename T> 20 T add(T a, T b, T m) { 21 return ((a += b) >= m) ? (a - m) : (a); 22 } 23 24 template <typename T> 25 T sub(T a, T b, T m) { 26 return ((a -= b) < 0) ? (a + m) : (a); 27 } 28 29 template <typename T> 30 void pcopy(T* pst, const T* ped, T* pval) { 31 for ( ; pst != ped; *(pst++) = *(pval++)); 32 } 33 34 template <typename T> 35 void pfill(T* pst, const T* ped, T val) { 36 for ( ; pst != ped; *(pst++) = val); 37 } 38 39 ll mul(ll a, ll b, ll m) { 40 // return (__int128)a * b % m; 41 ll rt = 0, pa = a; 42 for ( ; b; b >>= 1, pa = add(pa, pa, m)) 43 if (b & 1) 44 rt = add(rt, pa, m); 45 return rt; 46 } 47 48 ll qpow(ll a, ll p, ll m) { 49 ll rt = 1, pa = a; 50 for ( ; p; p >>= 1, pa = mul(pa, pa, m)) 51 if (p & 1) 52 rt = mul(rt, pa, m); 53 return rt; 54 } 55 56 ll gcd(ll a, ll b) { 57 return (b) ? (gcd(b, a % b)) : (a); 58 } 59 60 ll randLL() { 61 static ull seed = 998244353, msk = (1ull << 61) - 1; 62 return (signed ll) ((seed = seed * seed + seed + 233) & msk); 63 } 64 65 int pri[8] = {2, 3, 5, 7, 11, 13, 17, 19}; 66 67 boolean miller_rabin(ll n) { 68 static int T = 25; 69 for (int i = 0; i < 8; i++) 70 if (!(n % pri[i])) 71 return n == pri[i]; 72 if (n < 1000) { 73 for (int p = 2; p * p <= n; p++) 74 if (!(n % p)) 75 return false; 76 return true; 77 } 78 ll d = n - 1; 79 int s = 0; 80 while (!(d & 1)) 81 s++, d >>= 1; 82 for (int t = 0; t < T; t++) { 83 ll b = randLL() % n; 84 if (!b) 85 continue; 86 ll tmp = qpow(b, d, n); 87 if (tmp == 1 || tmp == n - 1) 88 continue; 89 for (int i = 0; i < s; i++) { 90 tmp = mul(tmp, tmp, n); 91 if (tmp == n - 1) 92 goto nextTurn; 93 if (tmp == 1 || tmp == 0) 94 return false; 95 } 96 if (tmp != 1) 97 return false; 98 nextTurn:; 99 } 100 return true; 101 } 102 103 ll pollard_rho(ll x) { 104 ll a, b, c, g; 105 if (!(x & 1)) 106 return 2; 107 while (true) { 108 b = a = randLL() % x; 109 c = randLL() % 127; 110 do { 111 a = add(mul(a, a, x), c, x); 112 b = add(mul(b, b, x), c, x); 113 b = add(mul(b, b, x), c, x); 114 g = gcd(b - a, x); 115 (g < 0) ? (g = -g) : (0); 116 if (g == x) 117 break; 118 if (g > 1) 119 return g; 120 } while (a != b); 121 } 122 assert(false); 123 return 0; 124 } 125 126 void get_primary_factors(ll x, vector<ll>& rt) { 127 if (miller_rabin(x)) { 128 rt.push_back(x); 129 return; 130 } 131 ll a = pollard_rho(x); 132 get_primary_factors(a, rt); 133 get_primary_factors(x / a, rt); 134 } 135 136 vector< pair<ll, int> > get_primary_factor(vector<ll>& vec) { 137 vector< pair<ll, int> > rt; 138 if (vec.empty()) 139 return rt; 140 sort(vec.begin(), vec.end()); 141 vector<ll>::iterator it = vec.begin(); 142 rt.push_back(make_pair(*it, 1)); 143 for (it = it + 1 ; it != vec.end(); it++) 144 if (*it == rt.back().first) 145 rt.back().second++; 146 else 147 rt.push_back(make_pair(*it, 1)); 148 return rt; 149 } 150 151 typedef vector< pair<ll, int> > factor; 152 153 /// Template ends 154 155 template <typename T> 156 class Matrix { 157 public: 158 T* p; 159 int r, c; 160 161 Matrix() : p(NULL) { } 162 Matrix(int r, int c) : r(r), c(c) { 163 p = new T[r * c]; 164 } 165 166 T* operator [] (int pos) { 167 return p + c * pos; 168 } 169 }; 170 171 const int Mod = 1e9 + 7; 172 173 int n; 174 ll *v; 175 int *f; 176 Matrix<int> F; 177 vector<int> *g; 178 vector<ll> va, vb; 179 vector<int> *diva, *divb, *mula, *mulb; 180 181 inline void init() { 182 scanf("%d", &n); 183 g = new vector<int>[(n + 1)]; 184 for (int i = 1, u, v; i < n; i++) { 185 scanf("%d%d", &u, &v); 186 g[u].push_back(v); 187 g[v].push_back(u); 188 } 189 v = new ll[(n + 2)]; 190 for (int i = 1; i <= n; i++) 191 scanf(Auto, v + i); 192 } 193 194 ll A = 1, B; 195 int *a, *b; 196 197 inline void discrete() { 198 vector<ll> _fac; 199 get_primary_factors(v[1], _fac); 200 factor fac = get_primary_factor(_fac); 201 202 random_shuffle(fac.begin(), fac.end()); 203 204 a = new int[(n + 1)]; 205 b = new int[(n + 1)]; 206 ll da = 1, db = 1; 207 for (auto p : fac) 208 db *= (p.second + 1); 209 for (auto p : fac) { 210 // cerr << p.first << " " << p.second << '\n'; 211 if (da * (p.second + 1) <= db / (p.second + 1)) { 212 da *= (p.second + 1), db /= (p.second + 1); 213 for (int j = 0; j < p.second; j++) 214 A *= p.first; 215 } 216 } 217 B = v[1] / A; 218 // cerr << da << " " << db << '\n'; 219 220 for (int i = 1; i <= n; i++) 221 va.push_back(gcd(v[i], A)); 222 for (int i = 1; i <= n; i++) 223 vb.push_back(gcd(v[i], B)); 224 225 sort(va.begin(), va.end()); 226 sort(vb.begin(), vb.end()); 227 va.erase(unique(va.begin(), va.end()), va.end()); 228 vb.erase(unique(vb.begin(), vb.end()), vb.end()); 229 230 // cerr << va.size() << ' ' << vb.size() << '\n'; 231 F = Matrix<int>(va.size(), vb.size()); 232 pfill(F[0], F[va.size()], 0); 233 for (int i = 1; i <= n; i++) { 234 a[i] = lower_bound(va.begin(), va.end(), gcd(v[i], A)) - va.begin(); 235 b[i] = lower_bound(vb.begin(), vb.end(), gcd(v[i], B)) - vb.begin(); 236 } 237 238 diva = new vector<int>[va.size()]; 239 divb = new vector<int>[vb.size()]; 240 mula = new vector<int>[va.size()]; 241 mulb = new vector<int>[vb.size()]; 242 for (int i = 0; i < (signed) va.size(); i++) { 243 for (int j = 0; j < (signed) va.size(); j++) { 244 if (!(va[i] % va[j])) 245 diva[i].push_back(j); 246 if (!(va[j] % va[i])) 247 mula[i].push_back(j); 248 } 249 } 250 for (int i = 0; i < (signed) vb.size(); i++) { 251 for (int j = 0; j < (signed) vb.size(); j++) { 252 if (!(vb[i] % vb[j])) 253 divb[i].push_back(j); 254 if (!(vb[j] % vb[i])) 255 mulb[i].push_back(j); 256 } 257 } 258 } 259 260 void dp(int p, int fa) { 261 if (p == 1) { 262 f[p] = 1; 263 } else { 264 for (auto x : mulb[b[p]]) 265 f[p] = add(f[p], F[a[p]][x], Mod); 266 } 267 for (auto x : diva[a[p]]) 268 F[x][b[p]] = add(F[x][b[p]], f[p], Mod); 269 for (auto e : g[p]) 270 if (e ^ fa) 271 dp(e, p); 272 for (auto x : diva[a[p]]) 273 F[x][b[p]] = sub(F[x][b[p]], f[p], Mod); 274 } 275 276 inline void solve() { 277 f = new int[(n + 1)]; 278 pfill(f + 1, f + n + 1, 0); 279 dp(1, 0); 280 for (int i = 1; i <= n; i++) 281 printf("%d\n", f[i]); 282 } 283 284 int main() { 285 srand((unsigned) time (NULL)); 286 init(); 287 discrete(); 288 solve(); 289 return 0; 290 }
Problem B 走路
显然,使得$(1, 1)$和$(n, n)$不连通的方案斜着放车。
然后随便容斥一下,得到:
$ans = n! - 2\sum_{i = 1}^{n}(n - i)! + 1 + \sum_{s = 2}^{n}(s - 1)(n - s)!$
发现需要阶乘,阶乘的前缀和以及阶乘的前缀和前缀和。
不会。分块大表。
laofu把数压成若干可见字符的方法真高级。
(请手动打表)
Code
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 typedef bool boolean; 5 6 const int n = 1e7, Mod = 1e9 + 7; 7 8 int add(int a, int b) { 9 return ((a += b) >= Mod) ? (a - Mod) : (a); 10 } 11 12 int sub(int a, int b) { 13 return ((a -= b) < 0) ? (a + Mod) : (a); 14 } 15 16 int mul(int a, int b) { 17 return (a * 1ll * b) % Mod; 18 } 19 20 void exgcd(int a, int b, int& x, int& y) { 21 if (!b) 22 x = 1, y = 0; 23 else { 24 exgcd(b, a % b, y, x); 25 y -= (a / b) * x; 26 } 27 } 28 29 int inv(int a, int n) { 30 int x, y; 31 exgcd(a, n, x, y); 32 return (x < 0) ? (x + n) : (x); 33 } 34 35 int fac[n + 1]; 36 int sfac[n + 1]; 37 int ssfac[n + 1]; 38 int ans[n + 1]; 39 40 inline void init() { 41 fac[0] = 1; 42 for (int i = 1; i <= n; i++) 43 fac[i] = mul(fac[i - 1], i); 44 sfac[0] = 1; 45 for (int i = 1; i <= n; i++) 46 sfac[i] = add(sfac[i - 1], fac[i]); 47 ssfac[0] = 1; 48 for (int i = 1; i <= n; i++) 49 ssfac[i] = add(ssfac[i - 1], sfac[i]); 50 // ans[1] = ans[2] = 0, ans[3] = 2; 51 // int reduce = 52 // for (in ti = 4; i <= n; i++) { 53 // ans[i] = add(ans[i - 1], fac[i]); 54 // ans[i] = sub(ans[i], fac[i - 1]); 55 // ans[i] = sub(ans[i], mul(fac[i - 1], 2)); 56 // ans[i] = add(ans[i], ) 57 // } 58 } 59 60 inline void solve() { 61 int T, n; 62 // cerr << fac[300000] << " " << sfac[300000] << " " << ssfac[300000] << '\n'; 63 scanf("%d", &T); 64 while (T--) { 65 scanf("%d", &n); 66 // int ans = fac[n]; 67 // for (int i = 1; i <= n; i++) 68 // ans = sub(sub(ans, fac[n - i]), fac[n - i]); 69 // ans = add(ans, 1); 70 // for (int s = 2; s <= n; s++) 71 // ans = add(ans, mul(s - 1, fac[n - s])); 72 int ans = ((n <= 2) ? 0 : add(fac[n], 1)); 73 if (n > 2) { 74 ans = sub(ans, mul(sfac[n - 1], 2)); 75 ans = add(ans, ssfac[n - 2]); 76 } 77 printf("%d\n", ans); 78 } 79 } 80 81 int main() { 82 init(); 83 solve(); 84 return 0; 85 }
Problem C 有趣的字符串题
好像SD有道是这道题的强制在线的版本,之前有人讲过分块做法。然后就一直陷入了分块的漩涡中。sad....
正解是考虑右端点在$r$的时候,询问左端点在每个位置时的答案。
考虑移动右端点至$r + 1$时产生的贡献。显然我们只用考虑它的回文border。
考虑一些长度构成等差数列的border。
对于每一段讨论它会产生贡献的部分。注意向前移动周期个字符的情形以及前一个这中间的最长串的前一个的出现的位置$[x, y]$。
若$z$是这些串中最短的一个串出现的左端点。不难得到当左端点在整数区间$(x, z]$中时,会有贡献。
对于不同的这样的border,显然每一组可以单独计算贡献。
因此我们用一个树状数组维护这个贡献,用线段树维护最后的出现位置,再用回文树维护border,就完事了。
时间复杂度$O(n\log^2n + m\log n)$。
Code
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <map> 7 using namespace std; 8 typedef bool boolean; 9 10 template <typename T> 11 void pfill(T* pst, const T* ped, T val) { 12 for ( ; pst != ped; *(pst++) = val); 13 } 14 15 typedef class Input { 16 protected: 17 const static int limit = 65536; 18 FILE* file; 19 20 int ss, st; 21 char buf[limit]; 22 public: 23 24 Input():file(NULL) { }; 25 Input(FILE* file):file(file) { } 26 27 void open(FILE *file) { 28 this->file = file; 29 } 30 31 void open(const char* filename) { 32 file = fopen(filename, "r"); 33 } 34 35 char pick() { 36 if (ss == st) 37 st = fread(buf, 1, limit, file), ss = 0;//, cerr << "str: " << buf << "ed " << st << endl; 38 return buf[ss++]; 39 } 40 }Input; 41 42 #define digit(_x) ((_x) >= '0' && (_x) <= '9') 43 44 Input& operator >> (Input& in, unsigned& u) { 45 char x; 46 while (~(x = in.pick()) && !digit(x)); 47 for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0'); 48 return in; 49 } 50 51 Input& operator >> (Input& in, unsigned long long& u) { 52 char x; 53 while (~(x = in.pick()) && !digit(x)); 54 for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0'); 55 return in; 56 } 57 58 Input& operator >> (Input& in, int& u) { 59 char x; 60 while (~(x = in.pick()) && !digit(x) && x != '-'); 61 int aflag = ((x == '-') ? (x = in.pick(), -1) : (1)); 62 for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0'); 63 u *= aflag; 64 return in; 65 } 66 67 Input& operator >> (Input& in, long long& u) { 68 char x; 69 while (~(x = in.pick()) && !digit(x) && x != '-'); 70 int aflag = ((x == '-') ? (x = in.pick(), -1) : (1)); 71 for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0'); 72 u *= aflag; 73 return in; 74 } 75 76 Input& operator >> (Input& in, char* str) { 77 for (char x; ~(x = in.pick()) && x != '\n' && x != ' '; *(str++) = x); 78 } 79 80 Input in (stdin); 81 82 const int alpha = 26; 83 84 typedef class TrieNode { 85 public: 86 int len, dif, g; 87 int in, out, id; 88 map<char, TrieNode*> ch; 89 TrieNode *fail, *slink; 90 }TrieNode; 91 92 typedef class PalindromeTree { 93 public: 94 int len; 95 TrieNode *pool; 96 TrieNode *top; 97 TrieNode *odd, *even; 98 TrieNode *last; 99 TrieNode **node; 100 char *str; 101 102 TrieNode* newnode(int len) { 103 top->id = top - pool; 104 top->len = len, top->dif = -1, top->g = 0; 105 // memset(top->ch, 0, sizeof(top->ch)); 106 top->fail = top->slink = NULL; 107 return top++; 108 } 109 110 PalindromeTree() { } 111 PalindromeTree(int n) { 112 node = new TrieNode*[(n + 5)]; 113 pool = new TrieNode[(n + 5)]; 114 str = new char[(n + 5)]; 115 top = pool, len = 0; 116 odd = newnode(-1), even = newnode(0); 117 odd->fail = odd, even->fail = odd; 118 odd->dif = even->dif = -1, last = even, str[0] = 0; 119 } 120 121 TrieNode* extend(TrieNode* p) { 122 while (str[len - p->len - 1] != str[len]) p = p->fail; 123 return p; 124 } 125 126 void append(char x) { 127 str[++len] = x; 128 int c = x - 'a'; 129 last = extend(last); 130 if (!last->ch[c]) { 131 TrieNode* p = newnode(last->len + 2); 132 p->fail = extend(last->fail)->ch[c]; 133 if (!p->fail) 134 p->fail = even; 135 last->ch[c] = p; 136 p->dif = p->len - p->fail->len; 137 138 if (p->dif == p->fail->dif) 139 p->slink = p->fail->slink; 140 else 141 p->slink = p->fail; 142 } 143 last = last->ch[c]; 144 node[len] = last; 145 } 146 147 void build(vector<int>* g) { 148 for (TrieNode* p = pool; p != top; p++) { 149 if (p->fail && p->fail != p) { 150 g[p->fail->id].push_back(p->id); 151 g[p->id].push_back(p->fail->id); 152 } 153 } 154 } 155 156 TrieNode* operator [] (int p) { 157 return node[p]; 158 } 159 }PalindromeTree; 160 161 typedef class Query { 162 public: 163 int l, r, id; 164 165 boolean operator < (Query p) const { 166 return r < p.r; 167 } 168 }Query; 169 170 typedef class SegTreeNode { 171 public: 172 int val; 173 SegTreeNode *l, *r; 174 175 SegTreeNode() : val(0), l(NULL), r(NULL) { } 176 177 void pushUp() { 178 val = max(l->val, r->val); 179 } 180 }SegTreeNode; 181 182 const int N = 3e5 + 5; 183 184 SegTreeNode pool[N << 2]; 185 SegTreeNode *top = pool; 186 187 SegTreeNode *newnode() { 188 return top++; 189 } 190 191 typedef class SegTree { 192 public: 193 int n; 194 SegTreeNode* rt; 195 196 SegTree() : rt(NULL) { } 197 SegTree(int n) : n(n) { 198 build(rt, 1, n); 199 } 200 201 void build(SegTreeNode*& p, int l, int r) { 202 p = newnode(); 203 if (l == r) 204 return ; 205 int mid = (l + r) >> 1; 206 build(p->l, l, mid); 207 build(p->r, mid + 1, r); 208 } 209 210 void modify(SegTreeNode *p, int l, int r, int idx, int val) { 211 if (l == r) { 212 p->val = val; 213 return ; 214 } 215 int mid = (l + r) >> 1; 216 if (idx <= mid) 217 modify(p->l, l, mid, idx, val); 218 else 219 modify(p->r, mid + 1, r, idx, val); 220 p->pushUp(); 221 } 222 223 int query(SegTreeNode* p, int l, int r, int ql, int qr) { 224 if (l == ql && r == qr) 225 return p->val; 226 int mid = (l + r) >> 1; 227 if (qr <= mid) 228 return query(p->l, l, mid, ql, qr); 229 if (ql > mid) 230 return query(p->r, mid + 1, r, ql, qr); 231 int a = query(p->l, l, mid, ql, mid); 232 int b = query(p->r, mid + 1, r, mid + 1, qr); 233 return (a > b) ? (a) : (b); 234 } 235 236 void modify(int idx, int val) { 237 modify(rt, 1, n, idx, val); 238 } 239 240 int query(int ql, int qr) { 241 return query(rt, 1, n, ql, qr); 242 } 243 }SegTree; 244 245 typedef class IndexedTree { 246 public: 247 int s; 248 int *a; 249 250 IndexedTree() { } 251 IndexedTree(int n) : s(n) { 252 a = new int[(n + 1)]; 253 pfill(a, a + n + 1, 0); 254 } 255 256 void add(int idx, int val) { 257 for ( ; idx <= s; idx += (idx & (-idx))) 258 a[idx] += val; 259 } 260 261 void add(int l, int r, int val) { 262 add(l, val), add(r + 1, -val); 263 } 264 265 int query(int idx) { 266 int rt = 0; 267 for ( ; idx; idx -= (idx & (-idx))) 268 rt += a[idx]; 269 return rt; 270 } 271 }IndexedTree; 272 273 const int Mod = 1e9 + 7; 274 275 int add(int a, int b) { 276 return ((a += b) >= Mod) ? (a - Mod) : (a); 277 } 278 279 int sub(int a, int b) { 280 return ((a -= b) < 0) ? (a + Mod) : (a); 281 } 282 283 int mul(int a, int b) { 284 return a * 1ll * b % Mod; 285 } 286 287 int n, m; 288 char *s; 289 Query* qs; 290 SegTree st; 291 vector<int> *g; 292 IndexedTree it; 293 PalindromeTree pt; 294 295 inline void init() { 296 in >> n >> m; 297 s = new char[(n + 5)]; 298 qs = new Query[(m + 1)]; 299 pt = PalindromeTree(n + 5); 300 g = new vector<int>[(n + 5)]; 301 in >> s; 302 for (int i = 0; i < n; i++) 303 pt.append(s[i]); 304 delete[] s; 305 pt.build(g); 306 for (int i = 1; i <= m; i++) 307 in >> qs[i].l >> qs[i].r, qs[i].id = i; 308 } 309 310 int dfs_clock; 311 void dfs(int p, int fa) { 312 pt.pool[p].in = ++dfs_clock; 313 // cerr << p << " " << fa << '\n'; 314 for (auto e : g[p]) 315 if (e ^ fa) 316 dfs(e, p); 317 pt.pool[p].out = dfs_clock; 318 } 319 320 int res = 0; 321 inline void solve() { 322 st = SegTree(n + 3); 323 it = IndexedTree(n); 324 dfs(0, -1); 325 sort(qs + 1, qs + m + 1); 326 327 Query* q = qs + 1, *qed = qs + m + 1; 328 for (int i = 1; i <= n; i++) { 329 for (TrieNode *p = pt[i]; p && p->len; p = p->slink) { 330 int left = max(st.query(p->in, p->out) - p->len + 1, 0) + 1; 331 int right = i - p->dif - ((p->slink) ? (p->slink->len) : (0)) + 1; 332 // cerr << i << " " << left << " " << right << '\n'; 333 it.add(left, right, 1); 334 } 335 st.modify(pt[i]->in, i); 336 while (q != qed && q->r == i) { 337 res = add(res, mul(it.query(q->l), q->id)); 338 // cerr << "Q: " << it.query(q->l) << " " << q->id << '\n'; 339 q++; 340 } 341 } 342 printf("%d\n", res); 343 } 344 345 int main() { 346 init(); 347 solve(); 348 return 0; 349 }