【 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

 

你可能感兴趣的:(test)