HDU 4622 Reincarnation
枚举字符串的起点,构造后缀自动机,每次插入一个字符,就能统计得到当前不同字串的个数,预处理出所有的询问。
1 #include<cstdio> 2 #include<cstring> 3 #define MAXN 2010 4 #define MAXM 26 5 int res[MAXN][MAXN]; 6 char str[MAXN]; 7 struct node { 8 node *next[MAXM]; 9 node *pre; 10 int step; 11 int tot; 12 } sam[MAXN << 1]; 13 node *root = &sam[0]; 14 int cnt, last; 15 int ans; 16 node &newNode() { 17 sam[++cnt].tot = 0; 18 memset(sam[cnt].next, 0, sizeof(sam[cnt].next)); 19 return sam[cnt]; 20 } 21 void add(int idx, int step) { 22 node &p = newNode(); 23 p.step = step; 24 p.pre = &p; 25 node *u = &sam[last]; 26 last = cnt; 27 while (u && u->next[idx] == 0) { 28 u->next[idx] = &p; 29 p.tot += u->tot; 30 u = u->pre; 31 } 32 if (!u) { 33 p.pre = root; 34 } else { 35 node *q = u->next[idx]; 36 if (q->step == u->step + 1) { 37 p.pre = q; 38 } else { 39 node &nq = newNode(); 40 memcpy(nq.next, q->next, sizeof(q->next)); 41 nq.step = u->step + 1; 42 nq.pre = q->pre; 43 q->pre = &nq; 44 p.pre = &nq; 45 for (; u && u->next[idx] == q; u = u->pre) { 46 u->next[idx] = &nq; 47 q->tot -= u->tot; 48 nq.tot += u->tot; 49 } 50 } 51 } 52 ans += p.tot; 53 } 54 int main() { 55 int T; 56 int i, j; 57 int len; 58 int q; 59 scanf("%d", &T); 60 while (T--) { 61 scanf(" %s", str); 62 len = strlen(str); 63 for (i = 0; i < len; i++) { 64 sam[0].pre = 0; 65 sam[0].tot = 1; 66 cnt = last = 0; 67 ans = 0; 68 memset(sam[cnt].next, 0, sizeof(sam[cnt].next)); 69 for (j = i; j < len; j++) { 70 add(str[j] - 'a', j - i + 1); 71 res[i][j] = ans; 72 } 73 } 74 scanf("%d", &q); 75 while (q--) { 76 scanf("%d%d", &i, &j); 77 printf("%d\n", res[i - 1][j - 1]); 78 } 79 } 80 return 0; 81 }
HDU 4623 Crime
dp[28][228]表示最后取的数,当前状态,可以得到的方案数。显然不可行。
由于相邻的两个数必须互素,所以这两个数不会有相同的素因子。
将1~n的数划分等价类,具有相同素因子的数属于同一个等价类。
通过打表可以发现,最后取的数减少到15,状态数减少到1728000。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<map> 5 #define MAXL 15 6 #define MAXN 30 7 #define MAXM 1728000 8 using namespace std; 9 vector<int> prime; 10 vector<int> factor; 11 map<int, int> mymap; 12 vector<int> g[MAXL]; 13 bool vis[MAXN]; 14 int dp[MAXM][MAXL]; 15 int base[MAXN]; 16 int stand[MAXN]; 17 int arr[MAXN]; 18 int tot; 19 bool isPrime(int n) { 20 for (int i = 2; i < n; i++) { 21 if (n % i == 0) { 22 return false; 23 } 24 } 25 return true; 26 } 27 int GCD(int x, int y) { 28 return y ? GCD(y, x % y) : x; 29 } 30 int encrypt() { 31 int res = 0; 32 for (int i = 0; i < tot; i++) { 33 res = res * base[i] + arr[i]; 34 } 35 return res; 36 } 37 void decrypt(int val) { 38 for (int i = tot - 1; i >= 0; i--) { 39 arr[i] = val % base[i]; 40 val /= base[i]; 41 } 42 } 43 int main() { 44 int T; 45 int n, m; 46 int i, j, k, l; 47 int tmp; 48 int ans; 49 pair<int, int> head, cur; 50 map<int, int>::iterator it; 51 scanf("%d", &T); 52 while (T--) { 53 scanf("%d%d", &n, &m); 54 mymap.clear(); 55 memset(vis, false, sizeof(vis)); 56 for (i = 1; i <= n; i++) { 57 for (j = 1; j <= n; j++) { 58 if (i == j) { 59 continue; 60 } 61 if (GCD(i, j) != 1) { 62 break; 63 } 64 } 65 if (j > n) { 66 vis[i] = true; 67 mymap[1]++; 68 } 69 } 70 prime.clear(); 71 for (i = 2; i <= n; i++) { 72 if (isPrime(i)) { 73 prime.push_back(i); 74 } 75 } 76 for (i = 1; i < (1 << prime.size()); i++) { 77 tmp = 1; 78 factor.clear(); 79 for (k = i, j = 0; k; k >>= 1, j++) { 80 if (k & 1) { 81 tmp *= prime[j]; 82 factor.push_back(prime[j]); 83 } 84 } 85 if (tmp <= n && !vis[tmp]) { 86 for (j = 1; j <= n; j++) { 87 for (k = 0; k < (int) factor.size(); k++) { 88 if (j % factor[k] != 0) { 89 break; 90 } 91 } 92 if (k >= (int) factor.size()) { 93 l = j; 94 for (k = 0; k < (int) factor.size(); k++) { 95 while (l % factor[k] == 0) { 96 l /= factor[k]; 97 } 98 } 99 if (l == 1) { 100 vis[l] = true; 101 mymap[tmp]++; 102 } 103 } 104 } 105 } 106 } 107 memset(dp, 0, sizeof(dp)); 108 tot = 0; 109 for (it = mymap.begin(); it != mymap.end(); it++) { 110 stand[tot] = (*it).first; 111 arr[tot] = (*it).second; 112 base[tot++] = (*it).second + 1; 113 } 114 l = encrypt(); 115 dp[l][0] = 1; 116 for (i = 0; i < tot; i++) { 117 g[i].clear(); 118 for (j = 0; j < tot; j++) { 119 if (GCD(stand[i], stand[j]) == 1) { 120 g[i].push_back(j); 121 } 122 } 123 } 124 for (i = l; i > 0; i--) { 125 decrypt(i); 126 for (j = 0; j < tot; j++) { 127 for (k = 0; k < (int) g[j].size(); k++) { 128 if (arr[g[j][k]] == 0) { 129 continue; 130 } 131 arr[g[j][k]]--; 132 l = encrypt(); 133 dp[l][g[j][k]] += dp[i][j]; 134 if (dp[l][g[j][k]] >= m) { 135 dp[l][g[j][k]] -= m; 136 } 137 arr[g[j][k]]++; 138 } 139 } 140 } 141 ans = 0; 142 for (i = 0; i < tot; i++) { 143 ans += dp[0][i]; 144 } 145 ans %= m; 146 for (i = 0; i < tot; i++) { 147 for (j = 1; j < base[i]; j++) { 148 ans *= j; 149 ans %= m; 150 } 151 } 152 printf("%d\n", ans); 153 } 154 return 0; 155 }
HDU 4627 The Unsolvable Problem
a+b=n,当a与b越接近,a*b越大。
寻找最接近的两个互素的数,答案最大。
1 #include<iostream> 2 typedef long long LL; 3 using namespace std; 4 LL GCD(LL x, LL y) { 5 return y ? GCD(y, x % y) : x; 6 } 7 int main() { 8 int T; 9 int n; 10 int tmp; 11 cin >> T; 12 while (T--) { 13 cin >> n; 14 for (int i = n >> 1; i <= n; i++) { 15 tmp = GCD(i, n - i); 16 if (tmp == 1) { 17 cout << (LL) i * (n - i) / tmp << endl; 18 break; 19 } 20 } 21 } 22 return 0; 23 }
HDU 4628 Pieces
dp[i]表示状态为i的最少步数。对i枚举子集,dp[i]=min(dp[j]+dp[i^j])。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define MAXN 16 5 #define oo 123456789 6 using namespace std; 7 char str[MAXN]; 8 int dp[1 << MAXN]; 9 bool isOK(int val) { 10 char tmp[MAXN]; 11 int len = 0; 12 for (int i = 0; val; val >>= 1, i++) { 13 if (val & 1) { 14 tmp[len++] = str[i]; 15 } 16 } 17 for (int i = 0, j = len - 1; i <= j; i++, j--) { 18 if (tmp[i] != tmp[j]) { 19 return false; 20 } 21 } 22 return true; 23 } 24 int dfs(int x) { 25 if (dp[x] != -1) { 26 return dp[x]; 27 } 28 int ans = oo; 29 for (int i = (x - 1) & x; i; i = (i - 1) & x) { 30 ans = min(ans, dfs(i) + dfs(x ^ i)); 31 } 32 dp[x] = ans; 33 return ans; 34 } 35 int main() { 36 int T; 37 int len; 38 scanf("%d", &T); 39 while (T--) { 40 memset(dp, -1, sizeof(dp)); 41 scanf(" %s", str); 42 len = strlen(str); 43 dp[0] = 0; 44 for (int i = 1; i < (1 << len); i++) { 45 if (isOK(i)) { 46 dp[i] = 1; 47 } 48 } 49 printf("%d\n", dfs((1 << len) - 1)); 50 } 51 return 0; 52 }
HDU 4630 No Pain No Game
枚举i,对于任意两个i的倍数,他们一定有约数i,有的等于它们的GCD,有的小于它们的GCD。
对i的倍数,在数列出现的位置排序,相邻的两个看成一个线段,线段有一个权值i。
问题转化为询问一个区间,能覆盖到的线段中,权值最大是多少。
离线处理,对询问右端点排序从小到大排序,对所有线段右端点从小到大排序。
每个询问[l,r],若线段[x,y]权值为val,对所有满足y<=r的线段插入线段树,插入的位置为x,权值为val。
回答询问即求询问区间的最大值。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #define MAXN 50010 6 #define MAXM 550000 7 using namespace std; 8 int arr[MAXN]; 9 int pos[MAXN]; 10 struct Query { 11 int x, y; 12 int index; 13 friend bool operator<(Query a, Query b) { 14 return a.y < b.y; 15 } 16 } ask[MAXN]; 17 struct node { 18 int x, y; 19 int val; 20 friend bool operator<(node a, node b) { 21 return a.y < b.y; 22 } 23 } p[MAXM]; 24 int tree[MAXN << 2]; 25 int ans[MAXN]; 26 void build(int L, int R, int rt) { 27 tree[rt] = 0; 28 if (L != R) { 29 int mid = (L + R) >> 1; 30 build(L, mid, rt << 1); 31 build(mid + 1, R, rt << 1 | 1); 32 } 33 } 34 inline void pushUp(int rt) { 35 tree[rt] = max(tree[rt << 1], tree[rt << 1 | 1]); 36 } 37 void update(int x, int val, int L, int R, int rt) { 38 if (L == R) { 39 tree[rt] = max(tree[rt], val); 40 } else { 41 int mid = (L + R) >> 1; 42 if (x <= mid) { 43 update(x, val, L, mid, rt << 1); 44 } else { 45 update(x, val, mid + 1, R, rt << 1 | 1); 46 } 47 pushUp(rt); 48 } 49 } 50 int query(int x, int y, int L, int R, int rt) { 51 if (x <= L && R <= y) { 52 return tree[rt]; 53 } else { 54 int mid = (L + R) >> 1; 55 int ans = 0; 56 if (x <= mid) { 57 ans = max(ans, query(x, y, L, mid, rt << 1)); 58 } 59 if (y > mid) { 60 ans = max(ans, query(x, y, mid + 1, R, rt << 1 | 1)); 61 } 62 return ans; 63 } 64 } 65 int main() { 66 int T; 67 int n, q; 68 int i, j; 69 int cnt; 70 vector<int> tmp; 71 scanf("%d", &T); 72 while (T--) { 73 scanf("%d", &n); 74 for (i = 1; i <= n; i++) { 75 scanf("%d", &arr[i]); 76 pos[arr[i]] = i; 77 } 78 scanf("%d", &q); 79 for (i = 0; i < q; i++) { 80 scanf("%d%d", &ask[i].x, &ask[i].y); 81 ask[i].index = i; 82 } 83 sort(ask, ask + q); 84 cnt = 0; 85 for (i = 1; i <= n; i++) { 86 tmp.clear(); 87 for (j = i; j <= n; j += i) { 88 tmp.push_back(pos[j]); 89 } 90 sort(tmp.begin(), tmp.end()); 91 for (j = 1; j < (int) tmp.size(); j++) { 92 p[cnt].x = tmp[j - 1]; 93 p[cnt].y = tmp[j]; 94 p[cnt++].val = i; 95 } 96 } 97 sort(p, p + cnt); 98 build(1, n, 1); 99 for (i = j = 0; i < q; i++) { 100 for (; j < cnt && p[j].y <= ask[i].y; j++) { 101 update(p[j].x, p[j].val, 1, n, 1); 102 } 103 ans[ask[i].index] = query(ask[i].x, ask[i].y, 1, n, 1); 104 } 105 for (i = 0; i < q; i++) { 106 printf("%d\n", ans[i]); 107 } 108 } 109 return 0; 110 }
HDU 4631 Sad Love Story
由于数据是随机的……
用set保存点集,按x坐标排序。
每次插入一个点后,从该位置沿x方向递增更新结果,当横坐标之差大于等于最近点对的时候,就跳出循环。
1 #include<cstdio> 2 #include<set> 3 #include<iostream> 4 typedef long long LL; 5 #define MAXN 500010 6 #define oo 123456789123456789LL 7 using namespace std; 8 struct Point { 9 int x, y; 10 Point(int _x = 0, int _y = 0) { 11 x = _x; 12 y = _y; 13 } 14 friend bool operator<(Point a, Point b) { 15 if (a.x != b.x) { 16 return a.x < b.x; 17 } else { 18 return a.y < b.y; 19 } 20 } 21 }; 22 set<Point> myset; 23 Point p[MAXN]; 24 inline LL dis2(Point a, Point b) { 25 LL x = a.x - b.x; 26 LL y = a.y - b.y; 27 return x * x + y * y; 28 } 29 inline LL dis1(Point a, Point b) { 30 LL x = a.x - b.x; 31 return x * x; 32 } 33 int main() { 34 int T; 35 int n; 36 int ax, bx, cx; 37 int ay, by, cy; 38 LL ans, res; 39 set<Point>::iterator it, tmp; 40 scanf("%d", &T); 41 while (T--) { 42 scanf("%d%d%d%d%d%d%d", &n, &ax, &bx, &cx, &ay, &by, &cy); 43 p[0] = Point(bx % cx, by % cy); 44 for (int i = 1; i < n; i++) { 45 p[i] = Point((p[i - 1].x * (LL) ax + bx) % cx, 46 (p[i - 1].y * (LL) ay + by) % cy); 47 } 48 res = oo; 49 ans = 0; 50 myset.clear(); 51 myset.insert(p[0]); 52 for (int i = 1; i < n; i++) { 53 if (myset.count(p[i])) { 54 break; 55 } 56 myset.insert(p[i]); 57 it = myset.find(p[i]); 58 for (tmp = it, ++tmp; tmp != myset.end(); ++tmp) { 59 if (dis1(*it, *tmp) >= res) { 60 break; 61 } else { 62 res = min(res, dis2(*it, *tmp)); 63 } 64 } 65 if (it != myset.begin()) { 66 for (tmp = it, --tmp;; --tmp) { 67 if (dis1(*it, *tmp) >= res) { 68 break; 69 } else { 70 res = min(res, dis2(*it, *tmp)); 71 } 72 if (tmp == myset.begin()) { 73 break; 74 } 75 } 76 } 77 ans += res; 78 } 79 cout << ans << endl; 80 } 81 return 0; 82 }