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 < b ? a : b;
6     printf(a&1 ? "Akshat" : "Malvika");
7     return 0;
8 }

Problem B Codeforces 451B

•题意:给你一个长度不超过10^5的数组,数组中的每个元素互不相同。

•问是否能翻转数组的某个区间,使得数组形成一个有序的升序序列。

•先按数组元素值的大小排序

•排完序之后,就能形成一个序列id[i]

•id[i]表示第i个数字在数组中的大小排名第几

•比如说:

•a[1]=1,a[2]=10,a[3]=6,a[4]=2,a[5]=11

•id[1]=1,id[2]=4,id[3]=3,id[4]=2,id[5]=5

•a[1]=1,a[2]=10,a[3]=6,a[4]=2,a[5]=11

•id[1]=1,id[2]=4,id[3]=3,id[4]=2,id[5]=5

•于是我们发现,如果我们能将id区间的某一段翻转过后,使得id[i]=i,那么就可以找到满足题意的区间

•找左端点L:第一个id[i]不等于i的端点

•找右端点R:第一个id[i]-id[i+1]不等于1的端点

•接下来我们需要验证剩余的i>R,id[i]是否等于i

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 const int maxn = 100010;
 5 struct Node{
 6     int val,id;
 7     bool operator < (const Node& rhs) const{
 8         return val < rhs.val;
 9     }
10 }node[maxn];
11
12 int main(){
13     int n,l = -1,r;
14     bool flag = 1;
15     scanf("%d",&n);
16     for(int i = 1;i <= n;i++){
17         scanf("%d",&node[i].val);
18         node[i].id = i;
19     }
20     sort(node+1,node+n+1);
21     node[n+1].id = -1;
22     for(int i = 1;i <= n;i++){
23         if(node[i].id != i){
24             l = i;
25             break;
26         }
27     }
28     if(l == -1){
29         printf("yes\n1 1\n");
30         return 0;
31     }
32     for(int i = l;i <= n;i++){
33         if(node[i].id - node[i+1].id != 1){
34             r = i;
35             break;
36         }
37     }
38     for(int i = r+1;i <= n;i++){
39         if(node[i].id != i){
40             flag = false;
41             break;
42         }
43     }
44     if(flag)    printf("yes\n%d %d\n",l,r);
45     else        printf("no\n");
46     return 0;
47 }

Problem C FZU 1907

•题意:给你一个字符串str,对于每个str长度为p的前缀,如果str[i]==str[p+i](p+i<len),那么我们认为它是一个periodic prefixs.求所有满足题意的前缀的长度p。

•知识点:KMP算法、对next数组的理解

•KMP算法中next数组的含义是什么?

•next数组:失配指针

•如果目标串的当前字符i在匹配到模式串的第j个字符时失配,那么我们可以让i试着去匹配next(j)

•对于模式串str,next数组的意义就是:

•如果next(j)=t,那么str[1…t]=str[len-t+1…len]

•我们考虑next(len),令t=next(len);

•next(len)有什么含义?

•str[1…t]=str[len-t+1…len]

•那么,长度为len-next(len)的前缀显然是符合题意的。

•接下来我们应该去考虑谁?

•t=next( next(len) );

•t=next( next (next(len) ) );

• 一直下去直到t=0,每个符合题意的前缀长是len-t

 1 #include <cstdio>
 2 #include <cstring>
 3 const int maxn = 1000010;
 4 int p[maxn],ans[maxn];
 5 char str[maxn];
 6
 7 void get_p(int len){
 8     p[1] = 0;
 9     int j = 0;
10     for(int i = 2;i <= len;i++){
11         while(j > 0 && str[j+1] != str[i])  j = p[j];
12         if(str[j+1] == str[i])  j++;
13         p[i] = j;
14     }
15 }
16
17 int main(){
18     int nkase;
19     scanf("%d",&nkase);
20     for(int kase = 1;kase <= nkase;kase++){
21         scanf("%s",str+1);
22         int len = strlen(str+1);
23         get_p(len);
24         int t = p[len],cnt = 0;
25         while(t){
26             ans[cnt++] = len-t;
27             t = p[t];
28         }
29         ans[cnt++] = len;
30         printf("Case #%d: %d\n",kase,cnt);
31         for(int i = 0;i < cnt-1;i++)  printf("%d ",ans[i]);
32         printf("%d\n",ans[cnt-1]);
33     }
34     return 0;
35 }

Problem D UVA 10608

•题意:一个镇上有N个人,他们之间有M组朋友关系。有一句名言说:“我朋友的朋友也是我的朋友”。问朋友最多的那个人能有多少朋友。

•考察内容:并查集的基本操作

•并操作

•查操作

•维护一个集合内元素的数量

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 const int maxn = 30010;
 5 int fa[maxn],num[maxn],ans;
 6
 7 int find(int u){
 8     return fa[u] == u ? u : fa[u] = find(fa[u]);
 9 }
10
11 void Union(int u,int v){
12     int a = find(u);
13     int b = find(v);
14     if(a != b){
15         fa[a] = b;
16         num[a] += num[b];
17         num[b] = num[a];
18         ans = max(ans,num[b]);
19     }
20 }
21
22 int main(){
23     int kase,n,m,a,b;
24     scanf("%d",&kase);
25     while(kase--){
26         scanf("%d%d",&n,&m);
27         for(int i = 1;i <= n;i++){
28             fa[i] = i;
29             num[i] = 1;
30         }
31         ans = 0;
32         for(int i = 0;i < m;i++){
33             scanf("%d%d",&a,&b);
34             Union(a,b);
35         }
36         printf("%d\n",ans);
37     }
38     return 0;
39 }

Problem E Codeforces 237C

•题意:给你一个闭区间[a,b],求一个最小的L,使得在区间[a,b-L+1]内任取一个数x,可以满足在x,x+1,x+2,……,x+L-2,x+L-1内至少包含k个素数。(1<=a,b,k<=10^6)

•考察内容:筛素数、二分

•一边筛素数,一边处理出一个前缀和sum

•sum(i)表示[1,i]中有多少素数

•那么我们每次查询区间[l,r]中有多少素数,直接查sum[r]-sum[l-1]就可以了

•接下去我们按照题意,对答案L进行二分就可以了

 1 #include <cstdio>
 2 #include <cstring>
 3 const int maxn = 1000010;
 4 int sum[maxn],a,b,k;
 5 bool pri[maxn];
 6 void init(){
 7     for(int i = 2;i < maxn;i++){
 8         sum[i] = sum[i-1];
 9         if(pri[i])  continue;
10         sum[i]++;
11         for(int j = i+i;j < maxn;j += i)
12             pri[j] = 1;
13     }
14 }
15
16 bool check(int mid){
17     for(int i = a;i <= b-mid+1;i++){
18         if(sum[i+mid-1]-sum[i-1] < k) return 0;
19     }
20     return 1;
21 }
22
23 int main(){
24     init();
25     scanf("%d%d%d",&a,&b,&k);
26     if(sum[b]-sum[a-1] < k){
27         printf("-1\n");
28         return 0;
29     }
30     int l = 1,r = b-a+1,ans;
31     while(l <= r){
32         int mid = (l+r)>>1;
33         if(check(mid))  ans = mid,r = mid-1;
34         else    l = mid+1;
35     }
36     printf("%d\n",ans);
37 }

Problem F Codeforces 16E

•题意:有n(n<=18)条鱼,接下来的n-1天,每天会有一对鱼(a,b)相遇,每天任意一对鱼相遇的概率是相等的,相遇之后,他们其中的一条会吃掉另外一条。

•鱼a吃掉鱼b的概率是p,那么鱼b吃掉鱼a的概率就是1-p;

•给你一个n*n的矩阵,表示n条鱼中的某对相遇时,互相吃掉对方的概率。

•数据保证pij+pji=1;

•计算每只鱼最后存活下来的概率。

•status{x1,x2,x3,x4,………xn-1,xn}表示每只鱼是否还活着的状态

•xi=1表示第i条鱼还活着

•xi=0表示第i条鱼已经被吃掉了

•dp(status)表示形成status这种状态的概率

•那么刚开始的时候(第一天),所有的鱼都活着。

•那么dp({1,1,1,1….,1,1,1})=1。

•假设当前状态status活着的鱼有t条

•此时,如果鱼j活着,鱼k也活着,那么j把k吃掉的概率是多少呢?

•P(j吃掉k)=P(j,k相遇)*P(相遇时j可以吃掉k)=1/C(t,2)*P(相遇时j可以吃掉k)

•dp(newstatus) += P(j吃掉k)*dp(status)

•newstatus:j吃掉k之后的新状态

 1 #include <cstdio>
 2 #include <cstring>
 3 double dp[1<<18];
 4 double mat[18][18];
 5
 6 int bitcount(int t){
 7     int ret = 0;
 8     while(t){
 9         ret += t&1;
10         t >>= 1;
11     }
12     return ret;
13 }
14
15 int main(){
16     int n;
17     scanf("%d",&n);
18     for(int i = 0;i < n;i++){
19         for(int j = 0;j < n;j++){
20             scanf("%lf",&mat[i][j]);
21         }
22     }
23     dp[(1<<n)-1] = 1;
24     for(int i = (1<<n)-1;i >= 1;i--){
25         int bit = bitcount(i);
26         if(bit == 1)    continue;
27         double p = 2*dp[i]/bit/(bit-1);
28         for(int j = 0;j < n;j++)if(i&(1<<j)){
29             for(int k = 0;k < n;k++)if(i&(1<<k)){
30                 dp[i^(1<<k)] += p*mat[j][k];
31             }
32         }
33     }
34     for(int i = 0;i < n;i++){
35         printf("%.6f ",dp[1<<i]);
36     }
37     return 0;
38 }

时间: 2024-10-13 22:50:08

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

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暑假集训基础组训练赛(4)解题报告

•Problem A SPOJ SUB_PROB   AC自动机 •题意: 给定一个长为M(M≤100000 )的文本串,和N(N≤1000)个长度不超过2000的模式串,问每个模式串是否在文本串中出现过? •几乎和周一课件上的第一个例题一模一样.. •把文本串丢到AC自动机里面去跑. •注意: •1.可能有两个相同的模式串(略坑吧.) •2.一个模式串可能是另一个模式串的后缀,即如果一个点的fail指针指向的点是一个“危险节点”,那么它本身也是一个“危险节点”. 1 #include <ios

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 就可以先到那个路口,观察新牛们有没有偷懒,而你的任务就是找出所有必经路口. [输入格式] 第一行两个用空格隔开的