【 2013 Multi-University Training Contest 3 】

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 }
View Code

 


 

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 }
View Code

 


 

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 }
View Code

 


 

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 }
View Code

 


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 }
View Code

 


 

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 }
View Code

 

转载于:https://www.cnblogs.com/DrunBee/p/3225899.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值