湖南省队集训 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
#include <algorithm>
#include <iostream>
#include <cassert>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <ctime>
#ifndef WIN32
#define Auto "%lld"
#else
#define Auto "%I64d"
#endif
using namespace std;
typedef bool boolean; #define ll long long
#define ull unsigned long long template <typename T>
T add(T a, T b, T m) {
return ((a += b) >= m) ? (a - m) : (a);
} template <typename T>
T sub(T a, T b, T m) {
return ((a -= b) < ) ? (a + m) : (a);
} template <typename T>
void pcopy(T* pst, const T* ped, T* pval) {
for ( ; pst != ped; *(pst++) = *(pval++));
} template <typename T>
void pfill(T* pst, const T* ped, T val) {
for ( ; pst != ped; *(pst++) = val);
} ll mul(ll a, ll b, ll m) {
// return (__int128)a * b % m;
ll rt = , pa = a;
for ( ; b; b >>= , pa = add(pa, pa, m))
if (b & )
rt = add(rt, pa, m);
return rt;
} ll qpow(ll a, ll p, ll m) {
ll rt = , pa = a;
for ( ; p; p >>= , pa = mul(pa, pa, m))
if (p & )
rt = mul(rt, pa, m);
return rt;
} ll gcd(ll a, ll b) {
return (b) ? (gcd(b, a % b)) : (a);
} ll randLL() {
static ull seed = , msk = (1ull << ) - ;
return (signed ll) ((seed = seed * seed + seed + ) & msk);
} int pri[] = {, , , , , , , }; boolean miller_rabin(ll n) {
static int T = ;
for (int i = ; i < ; i++)
if (!(n % pri[i]))
return n == pri[i];
if (n < ) {
for (int p = ; p * p <= n; p++)
if (!(n % p))
return false;
return true;
}
ll d = n - ;
int s = ;
while (!(d & ))
s++, d >>= ;
for (int t = ; t < T; t++) {
ll b = randLL() % n;
if (!b)
continue;
ll tmp = qpow(b, d, n);
if (tmp == || tmp == n - )
continue;
for (int i = ; i < s; i++) {
tmp = mul(tmp, tmp, n);
if (tmp == n - )
goto nextTurn;
if (tmp == || tmp == )
return false;
}
if (tmp != )
return false;
nextTurn:;
}
return true;
} ll pollard_rho(ll x) {
ll a, b, c, g;
if (!(x & ))
return ;
while (true) {
b = a = randLL() % x;
c = randLL() % ;
do {
a = add(mul(a, a, x), c, x);
b = add(mul(b, b, x), c, x);
b = add(mul(b, b, x), c, x);
g = gcd(b - a, x);
(g < ) ? (g = -g) : ();
if (g == x)
break;
if (g > )
return g;
} while (a != b);
}
assert(false);
return ;
} void get_primary_factors(ll x, vector<ll>& rt) {
if (miller_rabin(x)) {
rt.push_back(x);
return;
}
ll a = pollard_rho(x);
get_primary_factors(a, rt);
get_primary_factors(x / a, rt);
} vector< pair<ll, int> > get_primary_factor(vector<ll>& vec) {
vector< pair<ll, int> > rt;
if (vec.empty())
return rt;
sort(vec.begin(), vec.end());
vector<ll>::iterator it = vec.begin();
rt.push_back(make_pair(*it, ));
for (it = it + ; it != vec.end(); it++)
if (*it == rt.back().first)
rt.back().second++;
else
rt.push_back(make_pair(*it, ));
return rt;
} typedef vector< pair<ll, int> > factor; /// Template ends template <typename T>
class Matrix {
public:
T* p;
int r, c; Matrix() : p(NULL) { }
Matrix(int r, int c) : r(r), c(c) {
p = new T[r * c];
} T* operator [] (int pos) {
return p + c * pos;
}
}; const int Mod = 1e9 + ; int n;
ll *v;
int *f;
Matrix<int> F;
vector<int> *g;
vector<ll> va, vb;
vector<int> *diva, *divb, *mula, *mulb; inline void init() {
scanf("%d", &n);
g = new vector<int>[(n + )];
for (int i = , u, v; i < n; i++) {
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
v = new ll[(n + )];
for (int i = ; i <= n; i++)
scanf(Auto, v + i);
} ll A = , B;
int *a, *b; inline void discrete() {
vector<ll> _fac;
get_primary_factors(v[], _fac);
factor fac = get_primary_factor(_fac); random_shuffle(fac.begin(), fac.end()); a = new int[(n + )];
b = new int[(n + )];
ll da = , db = ;
for (auto p : fac)
db *= (p.second + );
for (auto p : fac) {
// cerr << p.first << " " << p.second << '\n';
if (da * (p.second + ) <= db / (p.second + )) {
da *= (p.second + ), db /= (p.second + );
for (int j = ; j < p.second; j++)
A *= p.first;
}
}
B = v[] / A;
// cerr << da << " " << db << '\n'; for (int i = ; i <= n; i++)
va.push_back(gcd(v[i], A));
for (int i = ; i <= n; i++)
vb.push_back(gcd(v[i], B)); sort(va.begin(), va.end());
sort(vb.begin(), vb.end());
va.erase(unique(va.begin(), va.end()), va.end());
vb.erase(unique(vb.begin(), vb.end()), vb.end()); // cerr << va.size() << ' ' << vb.size() << '\n';
F = Matrix<int>(va.size(), vb.size());
pfill(F[], F[va.size()], );
for (int i = ; i <= n; i++) {
a[i] = lower_bound(va.begin(), va.end(), gcd(v[i], A)) - va.begin();
b[i] = lower_bound(vb.begin(), vb.end(), gcd(v[i], B)) - vb.begin();
} diva = new vector<int>[va.size()];
divb = new vector<int>[vb.size()];
mula = new vector<int>[va.size()];
mulb = new vector<int>[vb.size()];
for (int i = ; i < (signed) va.size(); i++) {
for (int j = ; j < (signed) va.size(); j++) {
if (!(va[i] % va[j]))
diva[i].push_back(j);
if (!(va[j] % va[i]))
mula[i].push_back(j);
}
}
for (int i = ; i < (signed) vb.size(); i++) {
for (int j = ; j < (signed) vb.size(); j++) {
if (!(vb[i] % vb[j]))
divb[i].push_back(j);
if (!(vb[j] % vb[i]))
mulb[i].push_back(j);
}
}
} void dp(int p, int fa) {
if (p == ) {
f[p] = ;
} else {
for (auto x : mulb[b[p]])
f[p] = add(f[p], F[a[p]][x], Mod);
}
for (auto x : diva[a[p]])
F[x][b[p]] = add(F[x][b[p]], f[p], Mod);
for (auto e : g[p])
if (e ^ fa)
dp(e, p);
for (auto x : diva[a[p]])
F[x][b[p]] = sub(F[x][b[p]], f[p], Mod);
} inline void solve() {
f = new int[(n + )];
pfill(f + , f + n + , );
dp(, );
for (int i = ; i <= n; i++)
printf("%d\n", f[i]);
} int main() {
srand((unsigned) time (NULL));
init();
discrete();
solve();
return ;
}
Problem A
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
#include <iostream>
#include <cstdio>
using namespace std;
typedef bool boolean; const int n = 1e7, Mod = 1e9 + ; int add(int a, int b) {
return ((a += b) >= Mod) ? (a - Mod) : (a);
} int sub(int a, int b) {
return ((a -= b) < ) ? (a + Mod) : (a);
} int mul(int a, int b) {
return (a * 1ll * b) % Mod;
} void exgcd(int a, int b, int& x, int& y) {
if (!b)
x = , y = ;
else {
exgcd(b, a % b, y, x);
y -= (a / b) * x;
}
} int inv(int a, int n) {
int x, y;
exgcd(a, n, x, y);
return (x < ) ? (x + n) : (x);
} int fac[n + ];
int sfac[n + ];
int ssfac[n + ];
int ans[n + ]; inline void init() {
fac[] = ;
for (int i = ; i <= n; i++)
fac[i] = mul(fac[i - ], i);
sfac[] = ;
for (int i = ; i <= n; i++)
sfac[i] = add(sfac[i - ], fac[i]);
ssfac[] = ;
for (int i = ; i <= n; i++)
ssfac[i] = add(ssfac[i - ], sfac[i]);
// ans[1] = ans[2] = 0, ans[3] = 2;
// int reduce =
// for (in ti = 4; i <= n; i++) {
// ans[i] = add(ans[i - 1], fac[i]);
// ans[i] = sub(ans[i], fac[i - 1]);
// ans[i] = sub(ans[i], mul(fac[i - 1], 2));
// ans[i] = add(ans[i], )
// }
} inline void solve() {
int T, n;
// cerr << fac[300000] << " " << sfac[300000] << " " << ssfac[300000] << '\n';
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
// int ans = fac[n];
// for (int i = 1; i <= n; i++)
// ans = sub(sub(ans, fac[n - i]), fac[n - i]);
// ans = add(ans, 1);
// for (int s = 2; s <= n; s++)
// ans = add(ans, mul(s - 1, fac[n - s]));
int ans = ((n <= ) ? : add(fac[n], ));
if (n > ) {
ans = sub(ans, mul(sfac[n - ], ));
ans = add(ans, ssfac[n - ]);
}
printf("%d\n", ans);
}
} int main() {
init();
solve();
return ;
}
Problem B
Problem C 有趣的字符串题
好像SD有道是这道题的强制在线的版本,之前有人讲过分块做法。然后就一直陷入了分块的漩涡中。sad....
正解是考虑右端点在$r$的时候,询问左端点在每个位置时的答案。
考虑移动右端点至$r + 1$时产生的贡献。显然我们只用考虑它的回文border。
考虑一些长度构成等差数列的border。
对于每一段讨论它会产生贡献的部分。注意向前移动周期个字符的情形以及前一个这中间的最长串的前一个的出现的位置$[x, y]$。
若$z$是这些串中最短的一个串出现的左端点。不难得到当左端点在整数区间$(x, z]$中时,会有贡献。
对于不同的这样的border,显然每一组可以单独计算贡献。
因此我们用一个树状数组维护这个贡献,用线段树维护最后的出现位置,再用回文树维护border,就完事了。
时间复杂度$O(n\log^2n + m\log n)$。
Code
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <map>
using namespace std;
typedef bool boolean; template <typename T>
void pfill(T* pst, const T* ped, T val) {
for ( ; pst != ped; *(pst++) = val);
} typedef class Input {
protected:
const static int limit = ;
FILE* file; int ss, st;
char buf[limit];
public: Input():file(NULL) { };
Input(FILE* file):file(file) { } void open(FILE *file) {
this->file = file;
} void open(const char* filename) {
file = fopen(filename, "r");
} char pick() {
if (ss == st)
st = fread(buf, , limit, file), ss = ;//, cerr << "str: " << buf << "ed " << st << endl;
return buf[ss++];
}
}Input; #define digit(_x) ((_x) >= '0' && (_x) <= '9') Input& operator >> (Input& in, unsigned& u) {
char x;
while (~(x = in.pick()) && !digit(x));
for (u = x - ''; ~(x = in.pick()) && digit(x); u = u * + x - '');
return in;
} Input& operator >> (Input& in, unsigned long long& u) {
char x;
while (~(x = in.pick()) && !digit(x));
for (u = x - ''; ~(x = in.pick()) && digit(x); u = u * + x - '');
return in;
} Input& operator >> (Input& in, int& u) {
char x;
while (~(x = in.pick()) && !digit(x) && x != '-');
int aflag = ((x == '-') ? (x = in.pick(), -) : ());
for (u = x - ''; ~(x = in.pick()) && digit(x); u = u * + x - '');
u *= aflag;
return in;
} Input& operator >> (Input& in, long long& u) {
char x;
while (~(x = in.pick()) && !digit(x) && x != '-');
int aflag = ((x == '-') ? (x = in.pick(), -) : ());
for (u = x - ''; ~(x = in.pick()) && digit(x); u = u * + x - '');
u *= aflag;
return in;
} Input& operator >> (Input& in, char* str) {
for (char x; ~(x = in.pick()) && x != '\n' && x != ' '; *(str++) = x);
} Input in (stdin); const int alpha = ; typedef class TrieNode {
public:
int len, dif, g;
int in, out, id;
map<char, TrieNode*> ch;
TrieNode *fail, *slink;
}TrieNode; typedef class PalindromeTree {
public:
int len;
TrieNode *pool;
TrieNode *top;
TrieNode *odd, *even;
TrieNode *last;
TrieNode **node;
char *str; TrieNode* newnode(int len) {
top->id = top - pool;
top->len = len, top->dif = -, top->g = ;
// memset(top->ch, 0, sizeof(top->ch));
top->fail = top->slink = NULL;
return top++;
} PalindromeTree() { }
PalindromeTree(int n) {
node = new TrieNode*[(n + )];
pool = new TrieNode[(n + )];
str = new char[(n + )];
top = pool, len = ;
odd = newnode(-), even = newnode();
odd->fail = odd, even->fail = odd;
odd->dif = even->dif = -, last = even, str[] = ;
} TrieNode* extend(TrieNode* p) {
while (str[len - p->len - ] != str[len]) p = p->fail;
return p;
} void append(char x) {
str[++len] = x;
int c = x - 'a';
last = extend(last);
if (!last->ch[c]) {
TrieNode* p = newnode(last->len + );
p->fail = extend(last->fail)->ch[c];
if (!p->fail)
p->fail = even;
last->ch[c] = p;
p->dif = p->len - p->fail->len; if (p->dif == p->fail->dif)
p->slink = p->fail->slink;
else
p->slink = p->fail;
}
last = last->ch[c];
node[len] = last;
} void build(vector<int>* g) {
for (TrieNode* p = pool; p != top; p++) {
if (p->fail && p->fail != p) {
g[p->fail->id].push_back(p->id);
g[p->id].push_back(p->fail->id);
}
}
} TrieNode* operator [] (int p) {
return node[p];
}
}PalindromeTree; typedef class Query {
public:
int l, r, id; boolean operator < (Query p) const {
return r < p.r;
}
}Query; typedef class SegTreeNode {
public:
int val;
SegTreeNode *l, *r; SegTreeNode() : val(), l(NULL), r(NULL) { } void pushUp() {
val = max(l->val, r->val);
}
}SegTreeNode; const int N = 3e5 + ; SegTreeNode pool[N << ];
SegTreeNode *top = pool; SegTreeNode *newnode() {
return top++;
} typedef class SegTree {
public:
int n;
SegTreeNode* rt; SegTree() : rt(NULL) { }
SegTree(int n) : n(n) {
build(rt, , n);
} void build(SegTreeNode*& p, int l, int r) {
p = newnode();
if (l == r)
return ;
int mid = (l + r) >> ;
build(p->l, l, mid);
build(p->r, mid + , r);
} void modify(SegTreeNode *p, int l, int r, int idx, int val) {
if (l == r) {
p->val = val;
return ;
}
int mid = (l + r) >> ;
if (idx <= mid)
modify(p->l, l, mid, idx, val);
else
modify(p->r, mid + , r, idx, val);
p->pushUp();
} int query(SegTreeNode* p, int l, int r, int ql, int qr) {
if (l == ql && r == qr)
return p->val;
int mid = (l + r) >> ;
if (qr <= mid)
return query(p->l, l, mid, ql, qr);
if (ql > mid)
return query(p->r, mid + , r, ql, qr);
int a = query(p->l, l, mid, ql, mid);
int b = query(p->r, mid + , r, mid + , qr);
return (a > b) ? (a) : (b);
} void modify(int idx, int val) {
modify(rt, , n, idx, val);
} int query(int ql, int qr) {
return query(rt, , n, ql, qr);
}
}SegTree; typedef class IndexedTree {
public:
int s;
int *a; IndexedTree() { }
IndexedTree(int n) : s(n) {
a = new int[(n + )];
pfill(a, a + n + , );
} void add(int idx, int val) {
for ( ; idx <= s; idx += (idx & (-idx)))
a[idx] += val;
} void add(int l, int r, int val) {
add(l, val), add(r + , -val);
} int query(int idx) {
int rt = ;
for ( ; idx; idx -= (idx & (-idx)))
rt += a[idx];
return rt;
}
}IndexedTree; const int Mod = 1e9 + ; int add(int a, int b) {
return ((a += b) >= Mod) ? (a - Mod) : (a);
} int sub(int a, int b) {
return ((a -= b) < ) ? (a + Mod) : (a);
} int mul(int a, int b) {
return a * 1ll * b % Mod;
} int n, m;
char *s;
Query* qs;
SegTree st;
vector<int> *g;
IndexedTree it;
PalindromeTree pt; inline void init() {
in >> n >> m;
s = new char[(n + )];
qs = new Query[(m + )];
pt = PalindromeTree(n + );
g = new vector<int>[(n + )];
in >> s;
for (int i = ; i < n; i++)
pt.append(s[i]);
delete[] s;
pt.build(g);
for (int i = ; i <= m; i++)
in >> qs[i].l >> qs[i].r, qs[i].id = i;
} int dfs_clock;
void dfs(int p, int fa) {
pt.pool[p].in = ++dfs_clock;
// cerr << p << " " << fa << '\n';
for (auto e : g[p])
if (e ^ fa)
dfs(e, p);
pt.pool[p].out = dfs_clock;
} int res = ;
inline void solve() {
st = SegTree(n + );
it = IndexedTree(n);
dfs(, -);
sort(qs + , qs + m + ); Query* q = qs + , *qed = qs + m + ;
for (int i = ; i <= n; i++) {
for (TrieNode *p = pt[i]; p && p->len; p = p->slink) {
int left = max(st.query(p->in, p->out) - p->len + , ) + ;
int right = i - p->dif - ((p->slink) ? (p->slink->len) : ()) + ;
// cerr << i << " " << left << " " << right << '\n';
it.add(left, right, );
}
st.modify(pt[i]->in, i);
while (q != qed && q->r == i) {
res = add(res, mul(it.query(q->l), q->id));
// cerr << "Q: " << it.query(q->l) << " " << q->id << '\n';
q++;
}
}
printf("%d\n", res);
} int main() {
init();
solve();
return ;
}
Problem C
湖南省队集训 Day 2的更多相关文章
- [2018湖南省队集训] 6.24 T1 marshland
题面在这里! 一开始感觉像一个类似二分图的最小割,于是成功跑偏2333333 很容易发现一个关键性质,'L'的两个角落在的偶数格 的行(或者列)的奇偶性一定不同.... 于是我们再把偶数格按照行(或者 ...
- [2018湖南省队集训] 6.28 T3 simulate
这道模拟题出的我毫无脾气2333 最重要的是先要发现操作顺序不影响最后的答案,也就是每次随便挑一个>=2的数进行操作最后总是可以得到同样的数列. (这个还不太难想qwq) 但是最骚的是接下来的模 ...
- [2018湖南省队集训] 6.28 T2 color
毒瘤计数题2333,(小声)k其实可以出到1e9,不过这样求组合数的时候就要记1000种数的1~1000次下降幂(用到的组合数中第一维在1e9级别的只有1000种左右,第二维都是<=1000), ...
- JS省队集训记
不知不觉省队集训已经结束,离noi也越来越近了呢 论考前实战训练的重要性,让我随便总结一下这几天的考试 Day 1 T1 唉,感觉跟xj测试很像啊?meet in middle,不过这种题不多测是什么 ...
- [2018HN省队集训D9T1] circle
[2018HN省队集训D9T1] circle 题意 给定一个 \(n\) 个点的竞赛图并在其中钦定了 \(k\) 个点, 数据保证删去钦定的 \(k\) 个点后这个图没有环. 问在不删去钦定的这 \ ...
- [2018HN省队集训D8T1] 杀毒软件
[2018HN省队集训D8T1] 杀毒软件 题意 给定一个 \(m\) 个01串的字典以及一个长度为 \(n\) 的 01? 序列. 对这个序列进行 \(q\) 次操作, 修改某个位置的字符情况以及查 ...
- [2018HN省队集训D8T3] 水果拼盘
[2018HN省队集训D8T3] 水果拼盘 题意 给定 \(n\) 个集合, 每个集合包含 \([1,m]\) 中的一些整数, 在这些集合中随机选取 \(k\) 个集合, 求这 \(k\) 个集合的并 ...
- [2018HN省队集训D6T2] girls
[2018HN省队集训D6T2] girls 题意 给定一张 \(n\) 个点 \(m\) 条边的无向图, 求选三个不同结点并使它们两两不邻接的所有方案的权值和 \(\bmod 2^{64}\) 的值 ...
- [Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform
[Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform 题意 给定一个小写字母构成的字符串, 每个字符有一个非负权值. 输出所有满足权值和等于这个子串在所有本质 ...
随机推荐
- iOS代码组件化--利用cocoaPods创建私有库
如果项目模块多,模块间逻辑复杂,我们发现多个人同时维护一个代码仓库需要十分小心,一不小心,造成冲突,解决起来很烦,相信很多人都遇到手工删除合并的冲突的文件的经历. 如果利用组件化思想,每个人维护自己的 ...
- win7 64位系统下安装autoitlibrary库遇到问题解决
转载来自http://blog.sina.com.cn/s/blog_53f023270101skyq.html 今天需要在win7 64位系统下安装autoitlibrary库,起初安装好了robo ...
- 安卓demo
https://github.com/Blankj/AndroidUtilCode/blob/master/utilcode/README-CN.md
- python练习题-day23
1.人狗大战(组合) class Person: def __init__(self,name,hp,aggr,sex,money): self.name=name self.hp=hp self.a ...
- 问题记录 --Error parsing column 1 (Function_Num=10 - String)”
当C#查询数据库出现Error parsing column ## 的时候,首先去看看数据库里面该字段是什么类型,然后在看看你在创建model 的时候是什么类型,如果model的类型和数据库字段类型不 ...
- 关于SSD Trim功能
TRIM指令是微软联合各大SSD厂商所开发的一项技术,属于ATA8-ACS规范的技术指令. TRIM是告诉NAND闪存固态存储设备要擦除哪些数据的SATA接口指令.当相关页面的数据可以被覆盖时,操 ...
- 简单的C++输出日志
myLog.h #ifndef __myLog_H_ #define __myLog_H_ #include <stdio.h> #include <stdlib.h> #in ...
- FG面经Prepare: BST to Double LinkedList
BST to double linkedlist in inorder traversal sequenceFollow Up: 如果这个BST自带prev, next, 给一个value,插进去这个 ...
- android sdk 安装 配置
下载android sdk manager:http://dl.google.com/android/installer_r24.4.1-windows.exe 打开sdk manager 在tool ...
- DBC文件小结
Vector的DBC文件描述了CAN网络的通信规范,通过定义signal可以表示CAN帧中的各个物理信号的含义.通过CANdb++ Editor软件可以创建和修改DBC文件,一般监控或控制CAN网络内 ...