CSU-ACM暑假集训基础组训练赛(4)解题报告

•Problem A SPOJ SUB_PROB   AC自动机

•题意: 给定一个长为M(M≤100000 )的文本串,和N(N≤1000)个长度不超过2000的模式串,问每个模式串是否在文本串中出现过?

•几乎和周一课件上的第一个例题一模一样。。

•把文本串丢到AC自动机里面去跑。

•注意:

•1.可能有两个相同的模式串(略坑吧。)

•2.一个模式串可能是另一个模式串的后缀,即如果一个点的fail指针指向的点是一个“危险节点”,那么它本身也是一个“危险节点”。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <queue>
 6 using namespace std;
 7 const int maxn = 1000050 ;
 8 const int sigma_size = 52 ;
 9
10 int ID[1010] , tot ;
11 char text[100050] , word[2111] ;
12 bool flag[1010] ;
13 int son[maxn][sigma_size] , val[maxn] , f[maxn] , last[maxn] , q[maxn], sz ;
14
15 inline int idx(char c) {
16     if(c<=‘Z‘) return c - ‘A‘ ;
17     else return c - ‘a‘ + 26 ;
18 }
19
20 int Insert(char *s){
21     int u = 0 ;
22     for(int i=0 ; s[i] ; i++) {
23         int v = idx(s[i]) ;
24         if(!son[u][v]) son[u][v] = ++sz ;
25         u = son[u][v] ;
26     }
27     if(!val[u]) val[u] = ++tot ;
28     return val[u];
29 }
30
31 void get_fail() {
32     int rear = 0 ;
33     f[0] = 0 ;
34     for(int c=0; c<sigma_size ; c++) {
35         int u = son[0][c] ;
36         if(u) f[u] = last[u] = 0 , q[rear++] = u ;
37     }
38     for(int _i=0; _i<rear ; _i++) {
39         int u = q[_i] ;
40         for(int c=0; c<sigma_size; c++){
41             int v = son[u][c] ;
42             if(!v) { son[u][c] = son[f[u]][c] ; continue ; }
43             q[rear++] = v;
44             int x = f[u] ;
45             while(x && !son[x][c]) x = f[x] ;
46             f[v] = son[x][c] ;
47             last[v] = val[f[v]] ? f[v] : last[f[v]] ;
48         }
49     }
50 }
51
52 void print(int u){
53     while(u) {
54         flag[val[u]] = true ;
55         u = last[u] ;
56     }
57 }
58
59 void Find(char *s){
60     int j = 0;
61     for(int i=0; s[i] ; i++) {
62         int c=idx(s[i]);
63         while(j && !son[j][c]) j = f[j] ;
64         j = son[j][c] ;
65         print(j) ;
66     }
67 }
68
69 int main()
70 {
71     gets(text) ;
72     int n ;
73     scanf("%d", &n) ; getchar() ;
74     for(int i=1; i<=n; i++) {
75         scanf("%s" , word) ;
76         ID[i] = Insert(word);
77     }
78     Find(text) ;
79     for(int i=1; i<=n; i++) {
80         if(flag[ ID[i] ]) puts("Y") ;
81         else puts("N") ;
82     }
83     return 0 ;
84 }

•Problem B SPOJ DCEPC11I     线段树

•题意: 对一个长为N(N≤100000)的序列A[]进行Q(Q≤100000)次操作,2种操作:

•(1)“0  st  en” :  A[st]增加1 , A[st+1]增加2 ...... A[en]增加 en - st + 1 .

•(2)“1  st  en” :  询问区间和A[st] + A[st+1] + ..... + A[en]

•典型的线段树成段更新,成段查询。

•利用到的性质:两个等差数列对应项相加得到的任是等差数列。

•因此“懒惰标记”只需要记录首项a[]和公比d[]即可。

•要记得等差数列求和公式。

•数据类型的范围long long

•难点:标记记录什么,标记如何下传。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 typedef long long LL ;
 7 const int maxn = 100005 ;
 8
 9 #define Lson o<<1, L, mid
10 #define Rson o<<1|1 , mid+1 , R
11
12 LL a[maxn<<2] , d[maxn<<2] , sum[maxn<<2] ;
13
14 void pushup(int o){
15     sum[o] = sum[o<<1] + sum[o<<1|1] ;
16 }
17 void pushdown(int o , int c1 , int c2) {
18     if(a[o] || d[o]) {
19         LL a1 = a[o] , a2 = a[o] + (LL)d[o] * c1 ;
20         sum[o<<1] += a1*c1 + c1*(c1-1)*d[o]/2 ;
21         sum[o<<1|1] += a2*c2 + c2*(c2-1)*d[o]/2;
22         a[o<<1] += a1 , a[o<<1|1] += a2 ;
23         d[o<<1] += d[o] , d[o<<1|1] += d[o] ;
24         a[o] = d[o] = 0 ;
25     }
26 }
27
28 int l , r ;
29 void update(int o ,int L ,int R){
30     if(l<=L && R<=r) {
31         LL a1 = L - l + 1 , c1 = R - L + 1 ;
32         sum[o] += a1*c1 + c1*(c1-1)/2;
33         a[o] += a1 , d[o]++ ;
34         return ;
35     }
36     int mid = (L+R)>>1;
37     pushdown(o, mid-L+1 , R-mid);
38     if(l<=mid) update(Lson) ;
39     if(r>mid)  update(Rson) ;
40     pushup(o);
41 }
42
43 LL query(int o ,int L ,int R) {
44     if(l<=L && R<=r) return sum[o];
45     int mid = (L+R)>>1 ;
46     pushdown(o , mid-L+1 , R-mid) ;
47     LL ret = 0 ;
48     if(l<=mid) ret += query(Lson) ;
49     if(r> mid) ret += query(Rson) ;
50     return ret;
51 }
52
53 int main()
54 {
55     int N , Q;
56     scanf("%d%d", &N ,&Q);
57     while(Q--){
58         int op ;
59         scanf("%d%d%d", &op, &l ,&r) ;
60         if(op == 0) update(1, 1 , N) ;
61         else printf("%lld\n" , query(1, 1 ,N) ) ;
62     }
63     return 0;
64 }

•Problem C SPOJ RATING         二分、树状数组

•题意: 有N(N≤300000)coder, 每个coder[i]有两个属性A[i] 和 H[i] , 。

•当(A[i] ≥ A[j] && H[i] ≥ H[j]) && (A[i] > A[j] || H[i] > H[j]) 时,认为coder[i] 比 coder[j]优秀 ,问每个coder[i]比多少个其他的coder优秀?

•一个可行的方法:

•分为两类:

• ① A[i] >A[j] && H[i] >= H[j]

• ② A[i] == A[j] && H[i] > H[j]

•按属性A[]从小到大依次考虑每个coder[i] , 用树状数组动态维护所有在i前面 且 属性A比i的属性A小的  coder的属性H的信息 , 这样就可以在O(logn)统计第①类的个数, 第②类的个数随便搞搞就可以了。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 #define F first
 7 #define S second
 8 #define MP(a,b) make_pair( make_pair(a,b) , -1 )
 9 typedef pair< pair<int,int> , int> coder ;
10 const int maxn = 300010 ;
11 const int N = 100000 ;
12
13 int sum[N+1] , ans[maxn] ;
14 coder p[maxn] ;
15
16 inline int lowbit(int x){
17     return x & -x ;
18 }
19 void update(int x) {
20     for(; x<=N; x+=lowbit(x))  sum[x]++ ;
21 }
22 int query(int x) {
23     int ret = 0 ;
24     for(; x>0 ; x-=lowbit(x)) ret += sum[x] ;
25     return ret ;
26 }
27
28 int main()
29 {
30     int n ;
31     scanf("%d", &n);
32     for(int i=1; i<=n; i++)
33         scanf("%d%d", &p[i].F.F , &p[i].F.S) , p[i].S = i ;
34     sort(p+1 , p+1+n) ;
35     int y = 1;
36
37     for(int i=1; i<=n; i++) {
38         int u = p[i].S ;
39         while(y<i && p[y].F.F < p[i].F.F) {
40             update(p[y++].F.S) ;
41         }
42         ans[u] += query(p[i].F.S) ;
43         if(y < i) {
44             ans[u] += lower_bound(p+y , p+i , MP(p[i].F.F , p[i].F.S)) - p  - y ;
45         }
46     }
47
48     for(int i=1; i<=n; i++)
49         printf("%d\n" , ans[i]) ;
50
51     return 0;
52 }

•Problem D UVA - 10319          2-SAT

•详情见解题报告PPT

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 using namespace std;
 7 const int maxn = 65;
 8
 9 int N , M , K;
10 struct TwoSat{
11     int n ;
12     vector<int> g[maxn*2] ;
13     bool mark[maxn*2] ;
14     int S[maxn*2] , c;
15
16     bool dfs(int x) {
17         if(mark[x^1]) return false ;
18         if(mark[x] ) return true ;
19         mark[x] = true ;
20         S[c++] =  x ;
21         for(size_t i=0; i <g[x].size() ; i++)
22             if(!dfs(g[x][i])) return false ;
23         return true ;
24     }
25
26     void init(int n) {
27         this->n = n;
28         for(int i=0; i<n*2; i++) g[i].clear() ;
29         memset(mark , 0, sizeof(mark)) ;
30     }
31
32     void add(int u , int v) {
33         g[u].push_back(v) ;
34     }
35
36     bool solve() {
37         for(int i=0; i<n*2; i+=2) {
38             if(!mark[i] && !mark[i^1]) {
39                 c= 0 ;
40                 if(!dfs(i)) {
41                     while(c > 0) mark[S[--c]] = false ;
42                     if(!dfs(i^1)) return false ;
43                 }
44             }
45         }
46         return true ;
47     }
48 }t;
49
50 int main()
51 {
52     int T;
53     scanf("%d", &T) ;
54     while(T--) {
55         scanf("%d%d%d" ,&N ,&M, &K);
56         t.init(N+M) ;
57         int u1 , v1 , u2 , v2 ;
58         int p1 , p2 , p3 , p4 ;
59
60         while(K--) {
61             scanf("%d%d%d%d", &u1 ,&v1 , &u2 ,&v2)  ;
62             u1-- , u2-- , v1-- , v2-- ;
63             if(u1 == u2 && v1 == v2) continue ;
64             else if(u1 == u2) {
65                 p1 = u1*2 + (v1 < v2) ;
66                 t.add(p1^1 , p1) ;
67             }
68             else if(v1 == v2) {
69                 p1 = (N+v1)*2 + (u1 < u2) ;
70                 t.add(p1^1 , p1) ;
71             }
72             else {
73                 p1 = u1*2 + (v1 < v2);
74                 p2 = (N+v2)*2 + (u1 < u2) ;
75                 p3 = (N+v1)*2 + (u1 < u2) ;
76                 p4 = u2*2 + (v1 < v2) ;
77                 t.add(p1^1 , p3) , t.add(p1^1 , p4) ;
78                 t.add(p2^1 , p3) , t.add(p2^1 , p4) ;
79                 t.add(p3^1 , p1) , t.add(p3^1 , p2) ;
80                 t.add(p4^1 , p1) , t.add(p4^1 , p2) ;
81             }
82         }
83
84         if(t.solve()) puts("Yes") ;
85         else puts("No") ;
86     }
87     return 0;
88 }

•Problem E  AIZU 0024             签到题

 1 #include <iostream>
 2 #include <cmath>
 3 using namespace std;
 4 int main()
 5 {
 6        double y,t,mv;
 7        while(cin>>mv)
 8       {
 9               t=mv/9.8; y=t*t*4.9; double n=(y+5)/5;
10               cout<<ceil(n)<<endl;
11       }
12       return 0;
13      }

•Problem F  Codeforces 81A    模拟

•这是阮俊同学写的。

 1 #include <iostream>
 2 #include <string>
 3 #include <stack>
 4 using namespace std;
 5
 6
 7 int main()
 8 {
 9     string s;
10     cin>>s;
11     stack<char> sta;
12     for(int i=0;i<s.length();i++)
13     {
14         if(sta.empty())
15         {
16             sta.push(s.at(i));
17             continue;
18         }
19         char ch = sta.top();
20         if(s.at(i)!=ch)
21         {
22             sta.push(s.at(i));
23         }else
24         {
25             sta.pop();
26         }
27     }
28     stack<char> sta1;
29     while(!sta.empty())
30     {
31         sta1.push(sta.top());
32         sta.pop();
33     }
34     while(!sta1.empty())
35     {
36         cout<<sta1.top();
37         sta1.pop();
38     }
39
40     return 0;
41 }

CSU-ACM暑假集训基础组训练赛(4)解题报告

时间: 2024-12-18 03:44:55

CSU-ACM暑假集训基础组训练赛(4)解题报告的相关文章

CSU-ACM2014暑假集训基础组训练赛(1) 解题报告

•Problem A HDU 4450                 水题,签到题 水题..没啥好说的.给大家签到用的. 1 #include <cstdio> 2 int main(){ 3 int n,a,ans; 4 while(scanf("%d",&n),n){ 5 ans = 0; 6 for(int i = 0;i < n;i++){ 7 scanf("%d",&a); 8 ans += a*a; 9 } 10 pr

CSU-ACM暑假集训基础组训练赛(2) 解题报告

Problem A Codeforces 451A •题意:给你n+m根筷子,将他们分别水平.垂直放置,形成n*m个节点.两个人轮流选择一个点,将穿过这个点的两根筷子拿走,谁可以逼迫对方率先无法继续操作,谁就获胜,问获胜的是先手还是后手. •找规律即可.n,m中较小的那个数是奇数,先手胜,否则后手胜. 1 #include <cstdio> 2 int main(){ 3 int a,b; 4 scanf("%d%d",&a,&b); 5 a = a <

CSU-ACM暑假集训基础组七夕专场

•Problem A Codeforces 20C       最短路(dij,spfa) •题意:给出一张n个点m条边的无向图 (2 ≤ n ≤ 105, 0 ≤ m ≤ 105),输出从1到n的任意一条最短路径. •解法:dijkstra或者spfa,用pre数组记录到达每个点最短距离的前驱结点. •注意:路径的长度范围是 1 ≤ wi ≤ 106,从1到n的最短路径长度可能超出int范围. •没有路径从1到达n时要输出-1 1 #include <cstdio> 2 #include &

2015 暑假集训14级第一周周赛解题报告

A.小模拟题 根据要求模拟即可.没什么可讲的.. 参考代码:http://paste.ubuntu.com/11978075/ B.组合计数 首先排序,然后可以在O(n)复杂度内求出每个hero所能拿的sword的最大范围. 然后可以从第一个开始拿,考虑对于当前第i个hero来说,假设第i个hero最多能拿到第j个sword,那么首先这j个中一定有i-1个已经被前i-1个拿到了,所以第i个只能从后面的剩下的j-i个中选,于是可以拿j-i个.然后用高中学到的组合数学的知识,将每一个的可选个数乘起来

2014 UESTC 暑前集训队内赛(1) 解题报告

A.Planting Trees 排序+模拟 常识问题,将耗时排一个序,时间长的先种,每次判断更新最后一天的时间. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define Mod 1000000007 #define INT 2147483647 #define pi acos(-1.0)

「csp校内训练 2019-10-24」解题报告

「csp校内训练 2019-10-24」解题报告 T1.猴猴吃苹果 \(Description\) 猴猴最喜欢在树上玩耍,一天猴猴又跳上了一棵树,这棵树有 \(N \ (N \leq 50000)\) 个苹果,每个苹果有一个编号,分别为 \(0\) ~ \(N - 1\) 它们之间由 \(N-1\) 个树枝相连,猴猴可以从树枝的一端爬到树枝的另一端,所以猴猴可以从任意一个苹果的位置出发爬到任意猴猴想去的苹果的位置. 猴猴开始在编号为 \(K \ (K < N)\) 的苹果的位置,并且把这个苹果吃

「csp校内训练 2019-10-30」解题报告

「csp校内训练 2019-10-30」解题报告 T1.树 题目链接(逃) \(Description\): 现在有一棵树,共 \(N\) 个节点. 规定:根节点为 \(1\) 号节点,且每个节点有一个点权. 现在,有 \(M\) 个操作需要在树上完成,每次操作为下列三种之一: \(1 \ x \ a\):操作 \(1\),将节点 \(x\) 点权增加 \(a\). \(2 \ x \ a\):操作 \(2\),将以节点 \(x\) 为根的子树中所有点的权值增加 \(a\). \(3 \ x\)

ACM暑假集训总结

暑假集训总结 回想去年暑假集训,和boblee.yyd组队时,他们为了复习考研,只有我一人默默的在基地训练,再到今年和yj.cq组队,三人能在基地一起刷题训练.再回想去年暑假自己作为新人,只能抱着两位队友的大腿,到今年作为一队的成员,要挑起集训队的大梁.从去年的全俱乐部开黑只能压线过几场网络赛,再到今年的队伍间各自做题,照样能没什么压力的通过网赛.亲眼见证俱乐部由弱到强,由不为人知到众所周知,自己不仅感触颇多,也同样敬佩起当初办起这个俱乐部的创始人们. 作为一个刚刚接触OI就要面临高考的人,才刚

暑假第二次考试 冲刺Noip2017模拟赛2 解题报告——五十岚芒果酱

题1 牛跑步(running) [题目描述] 新牛到部队,CG 要求它们每天早上搞晨跑,从 A 农场跑到 B 农场.从 A 农场到 B 农场中有 n-2 个路口,分别标上号,A 农场为 1 号,B 农场为 n 号,路口分别为 2...n-1 号,从 A 农场到 B 农场有很多条路径可以到达,而 CG 发现有的路口是必须经过的,即每条路径都经过的路口,CG 要把它们记录下来,这样 CG 就可以先到那个路口,观察新牛们有没有偷懒,而你的任务就是找出所有必经路口. [输入格式] 第一行两个用空格隔开的