10.01QBXT集训

a
【问题描述】
你是能看到第一题的 friends呢。
—— hja
何大爷对字符串十分有研究,于是天出题虐杀 zhx。何大爷今天为 何大爷今天为 字符串定义了新的权值计算方法。一个由小写母组成,被定义为其中出现次数最多的字符减去少。(注 被定义为其中出现次数最多的字符减去少。(注 意,在讨论出现最少的字符时候该必须至一次)何大爷给你一个字符串,何大爷想知道这的所有子中权值最是多少?
【输入格式】
第一行 一个整数 𝑛,代表字符串的长度 。
接下来一行 𝑛个小写字母,代表该符串。
【输出格式】
一行个整数代表答案。
【样例输入】
10
aabbaaabab
【样例输出】
3
【数据范围与规定】
对于 30%的数据, 1≤𝑛≤100。
对于 60%的数据, 1≤𝑛≤1000。
对于 100%的数据, 1≤𝑛≤10^6.

思路分析:大概需要一个前缀和维护最大值最小值。

30分做法:两层for循环枚举l与r,暴力统计l到r之间的字符出现次数,然后暴力排序一次,输出答案。

60分做法:右端点每次都移动1个位置,所以可以使用前缀和维护最大值最小值。对每个字符预处理前缀和。

100分做法:对于每一个字符记录前缀和,然后空间复杂度大概是$O(26\times \text{str.length()}$.时间复杂度可以降到$O(26*2*n)$。

code by zhx, comment by Mingqi_H.

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<vector>
 5 
 6 using namespace std;
 7 
 8 const int maxn=1000010;
 9 
10 int n,ans,p[26][26],minv[26][26],sum[26],last[26];
11 
12 char s[maxn];
13 
14 int main()
15 {
16 //    freopen("a.in","r",stdin);
17 //    freopen("a.out","w",stdout);
18 
19     scanf("%d",&n);
20     scanf("%s",s+1);
21     for (int a=1;a<=n;a++)
22     {
23         int c=s[a]-'a';//暂存一下字符串的当前字符 
24         sum[c]++;//对这个字符进行前缀和处理 
25         last[c]=a;//保存这个字符最后一次出现的位置 
26         for (int b=0;b<26;b++)
27             if (b!=a && sum[b])//如果端点不重合(至少取两个字符构成子串),并且这个字符出现过 
28                 ans=max(ans,
29                     max(sum[c]-sum[b]-minv[c][b]-(last[b]==p[c][b]),
30                     sum[b]-sum[c]-minv[b][c]-(last[b]==p[b][c])));
31         for (int b=0;b<26;b++)//对于每一个字符 
32         {
33             if (sum[c]-sum[b]<minv[c][b]) 
34                 minv[c][b]=sum[c]-sum[b],p[c][b]=a;//前缀和维护一下最小值 
35             if (sum[b]-sum[c]<minv[b][c]) //同上 
36                 minv[b][c]=sum[b]-sum[c],p[b][c]=a;
37         }
38     }
39     printf("%d\n",ans);
40 
41     return 0;
42 }
a

附get到的dalao听课笔记:

远超NOIPT1
30:枚举l,r
两重for,将区间扫一遍
60:思考这一做法
右端点每次向右移动一个位置
因此每一个字符都可以预处理前缀和
这样可以拿到60分
70:上述做法需要$26^2$次
由于对某一字符对另25个字符没有必要枚举
可以优化一下(并没有听懂
90:考虑假设字符串s,希望算得[L,R]的权值
这就相当于统计字符的频次
对每一个字符记录一个前缀和
则quanzhi[l][r]为sum[k][r]-sum[k][l-1]-sum[j][r]+sum[j][l-1]
若枚举R,我们希望找到L使得结果最大
就可以让sum[k][l-1]-sum[j][l-1]
这里可以再找一个前缀最小值维护
即sum[k][j][x]表示前x个sum[k][x]-sum[j][x]
复杂度O(n*26*26)
100:同70,O(n*26)
record

b
【问题描述】
你是能看到第二题的 friends呢。
—— laekov
Hja和 Yjq在玩捉迷藏。 在玩捉迷藏。 Yjq躲了起来, Hja要找他。在们玩游戏的房间 里,只有一堵不透明的墙和个双面镜子。 里,只有一堵不透明的墙和个双面镜子。 Hja和 Yjq可以看作平面上坐标分 别为 (𝑋𝑣,𝑌𝑣)和(𝑋𝑝,𝑌𝑝)的点。墙是一条连接 的点。墙是一条连接 (𝑋𝑤1,𝑌𝑤1)和(𝑋𝑤2,𝑌𝑤2)的线段,镜子是 的线段,镜子是 一条连接 (𝑋𝑚1,𝑌𝑚1)和(𝑋𝑚2,𝑌𝑚2)的线段。
如果 视线和障碍物有公共点,那么我们认为会被阻挡无法看见。如果 视线和障碍物有公共点,那么我们认为会被阻挡无法看见。如果 视线和障碍物有公共点,那么我们认为会被阻挡无法看见。如果 视线和障碍物有公共点,那么我们认为会被阻挡无法看见。视线和镜子有公共点,那么我们认为发生了反射。的过程遵循物理规律 视线和镜子有公共点,那么我们认为发生了反射。的过程遵循物理规律 视线和镜子有公共点,那么我们认为发生了反射。的过程遵循物理规律 —— 入射角等于反,且光线与在镜子同侧。也就是说想要看见对 入射角等于反,且光线与在镜子同侧。也就是说想要看见对 入射角等于反,且光线与在镜子同侧。也就是说想要看见对 入射角等于反,且光线与在镜子同侧。也就是说想要看见对 方, Hja和 Yjq必须在镜子的同一侧,包括所直线上(参见样例 必须在镜子的同一侧,包括所直线上(参见样例 必须在镜子的同一侧,包括所直线上(参见样例 1)。 如果 视线与镜子重合,那么不会发生反射并且被当作障碍物(参见样例 视线与镜子重合,那么不会发生反射并且被当作障碍物(参见样例 视线与镜子重合,那么不会发生反射并且被当作障碍物(参见样例 视线与镜子重合,那么不会发生反射并且被当作障碍物(参见样例 4)。
Hja很想知道他站在原地能否看见 Yjq,帮助他解决这个问题。
【输入格式】
第一行两个数 𝑋𝑣,𝑌𝑣,表示 Hja的坐标。
第二行两个数 𝑋𝑝,𝑌𝑝表示 Yjq的坐标。
第三行四个数 𝑋𝑤1,𝑌𝑤1,𝑋𝑤2,𝑌𝑤2,分别表示墙的两个端点坐标。
第四行个数 𝑋𝑚1,𝑌𝑚1,𝑋𝑚2,𝑌𝑚2,分别表示镜子的两个端点坐标。
【输出格式】
如果 Hja站在原地能看到 Yjq,则输出 "YES",否则输出 "NO"。
【样例输入1】
-1 3
1 3
0 2 4
0 1
【样例输出1】
NO

【样例输入2】
0
1
0
1 -100 -100 -101 -101
【样例输出2】
NO
【样例输入3】
0
1
0
1 -1 3
【样例输出3】
YES
【样例输入4】
0
10 0
100 101
1 0
3 【样例输出4】
YES
【数据规模与约定】
对于 100%的数据, 所有坐标均为绝对值不超过 所有坐标均为绝对值不超过 104的整数。输入线段不会 的整数。输入线段不会 退化成点,且两条线段没有交。 退化成点,且两条线段没有交。 Hja和 Yjq的位置不同,且在任何一条线段 的位置不同,且在任何一条线段 上

思路分析:一看...这不计算几何吗?随机输出一下搞一点事情。预估得分:44-66分(考试得分:46),当然更换一下随机算法还能更好一些(输出NO得分54)。但对于多组数据gg.

正解计算几何:已知能看到只有两种情况。先判断一下是否有墙、是否在镜子的两侧,如果遇到这种情况就直接输出NO,否则作点关于镜子所在直线的对称点,然后再连一条边,判断是否与镜子有交点,如果有交点就输出YES,否则输出NO。

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 using namespace std;
  7 const double eps=1e-8;
  8 int sgn(double a)
  9 {
 10     if (fabs(a)<eps) return 0;
 11     else
 12     {
 13         if (a>0.0) return 1;
 14         else return -1;
 15     }
 16 }
 17 struct point
 18 {
 19     double x,y;
 20     point(){}
 21     point(double a,double b)
 22     {
 23         x=a;y=b;
 24     }
 25     void init()
 26     {
 27         scanf("%lf%lf",&x,&y);
 28     }
 29     point operator+(const point &a)const
 30     {
 31         point ans;
 32         ans.x=x+a.x;
 33         ans.y=y+a.y;
 34         return ans;
 35     }
 36     point operator-(const point &a)const
 37     {
 38         point ans;
 39         ans.x=x-a.x;
 40         ans.y=y-a.y;
 41         return ans;
 42     }
 43     point operator*(const double &a)const
 44     {
 45         point ans;
 46         ans.x=x*a;
 47         ans.y=y*a;
 48         return ans;
 49     }
 50     void print()
 51     {
 52         printf("%lf %lf\n",x,y);
 53     }
 54 }v,p,w1,w2,m1,m2;
 55 double cross(point a,point b)
 56 {
 57     return a.x*b.y-a.y*b.x;
 58 }
 59 double dot(point a,point b)
 60 {
 61     return a.x*b.x+a.y*b.y;
 62 }
 63 bool cross(point p1,point p2,point p3,point p4)
 64 {
 65     if (sgn(cross(p2-p1,p3-p1))*sgn(cross(p2-p1,p4-p1))==1) return false;
 66     if (sgn(cross(p4-p3,p1-p3))*sgn(cross(p4-p3,p2-p3))==1) return false;
 67     if (sgn(max(p1.x,p2.x)-min(p3.x,p4.x))==-1) return false;
 68     if (sgn(max(p1.y,p2.y)-min(p3.y,p4.y))==-1) return false;
 69     if (sgn(max(p3.x,p4.x)-min(p1.x,p2.x))==-1) return false;
 70     if (sgn(max(p3.y,p4.y)-min(p1.y,p2.y))==-1) return false;
 71     return true;
 72 }
 73 point getcross(point p1,point p2,point p3,point p4)
 74 {
 75     double a=p2.y-p1.y;
 76     double b=p1.x-p2.x;
 77     double c=-p1.x*p2.y+p1.y*p2.x;
 78     double d=p4.y-p3.y;
 79     double e=p3.x-p4.x;
 80     double f=-p3.x*p4.y+p3.y*p4.x;
 81     double x=(b*f-c*e)/(a*e-b*d);
 82     double y=(a*f-c*d)/(b*d-a*e);
 83     return point(x,y);
 84 }
 85 point calcfoot(point p1,point p2,point p3)
 86 {
 87     double ratio=dot(p1-p2,p3-p2)/dot(p3-p2,p3-p2);
 88     return p2+(p3-p2)*ratio;
 89 }
 90 bool check()
 91 {
 92     if (!cross(v,p,w1,w2))
 93     {
 94         if (!cross(v,p,m1,m2)) return true;
 95         if (sgn(cross(m1-v,m2-v))==0 && sgn(cross(m1-p,m2-p)==0)) return true;      
 96     }
 97     if (sgn(cross(m2-m1,v-m1))*sgn(cross(m2-m1,p-m1))==1)
 98     {
 99         point foot=calcfoot(p,m1,m2);
100         foot=foot*2.0-p;
101         if (cross(v,foot,m1,m2))
102         {
103             foot=getcross(v,foot,m1,m2);
104             if (!cross(v,foot,w1,w2) && !cross(foot,p,w1,w2)) return true;
105         }
106     }
107     return false;
108 }
109 int main()
110 {
111     freopen("b.in","r",stdin);
112     freopen("b.out","w",stdout);
113     v.init();
114     p.init();
115     w1.init();
116     w2.init();
117     m1.init();
118     m2.init();
119     if (check()) printf("YES\n");
120     else printf("NO\n");
121     return 0;
122 }
b

c
【问题描述】
你是能看到第三题的 friends呢。
—— aoao
众所周知 ,八数码 问题 是一个 非常 难的问题 ,但是 Yjq非常 有面子 ,他把这 道题 简化了 一番 。现在 给了 你一个 3×3的方格图 ,你的 目标 是通过 不断 移动 使得 相邻 颜色 的块形成联通 块。你每次 的移动 方式 是选择 一列 或者 一行 进行 置换 滑动 (这个 解释 起来 比较 麻烦 ,看下面 的图就懂了 )。所谓 置换 滑动 ,就是 所有 格子 沿着 给定 的方向 顺次 移动 ,最后 一个 格子 会被 置换到 最前面 的过程 。现在 给定 整 个方格图 ,以及 每个 格子 是否 能够 移动 ,求使得 相同 颜色 联通 的最小步数 。
【输入格式】
输入 为3×3的方格图 ,每个 位置 由五个字符 组成 ,前四个字符 分别 表示 上下 左右 四个 部分 的颜色 ,第五个 字符 表示 该格子 是否 能够 移动 ,其中 0是能移动 1是 不能移动 。
【输出格式】
一行个整数代表答案。
【样例输入】
GGGG0
OGOO0
GGGG0 OOOO0
OGGG1 【样例输出】
5
【样例解释】

【数据规模与约定】
对于 100%的数据 ,所有颜色 只可能是 RGBO中的一种 ,且一定 有解 。

思路分析:搜索。

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<queue>
  5 
  6 using namespace std;
  7 
  8 #define get(a,b,c) ((a-1)*12+(b-1)*4+c)
  9 
 10 int en,tmp[4][4],color[37],map[9][5],q[37],nowmap[4][4],newmap[4][4];
 11 
 12 bool num[9],use[90000000],right[37],row[4],col[4],col_find[5];
 13 
 14 char s[10];
 15 
 16 struct rec
 17 {
 18     int sta,step;
 19     rec(){}
 20     rec(int a,int b)
 21     {
 22         sta=a;step=b;
 23     }
 24 };
 25 
 26 queue<rec> que;
 27 
 28 struct edge
 29 {
 30     int e;
 31     edge *next;
 32 }*v[37],ed[100];
 33 
 34 void add_edge(int s,int e)
 35 {
 36     en++;
 37     ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;
 38     en++;
 39     ed[en].next=v[e];v[e]=ed+en;v[e]->e=s;
 40 }
 41 
 42 bool check(int nows)
 43 {
 44     memset(num,false,sizeof(num));
 45     for (int a=3;a>=1;a--)
 46         for (int b=3;b>=1;b--)
 47             if (a!=3 || b!=3)
 48             {
 49                 tmp[a][b]=nows%10;
 50                 num[nows%10]=true;
 51                 nows/=10;
 52             }
 53     for (int a=0;a<9;a++)
 54         if (!num[a])
 55         {
 56             tmp[3][3]=a;
 57             break;
 58         }
 59     int cnt=0;
 60     for (int a=1;a<=3;a++)
 61         for (int b=1;b<=3;b++)
 62             for (int c=1;c<=4;c++)
 63             {
 64                 cnt++;
 65                 color[cnt]=map[tmp[a][b]][c];
 66             }
 67     memset(right,false,sizeof(right));
 68     memset(col_find,false,sizeof(col_find));
 69     for (int a=1;a<=36;a++)
 70         if (!right[a])
 71         {
 72             if (col_find[color[a]]) return false;
 73             col_find[color[a]]=true;
 74             int front=1,tail=1;
 75             q[1]=a;
 76             right[a]=true;
 77             for (;front<=tail;)
 78             {
 79                 int now=q[front++];
 80                 for (edge *e=v[now];e;e=e->next)
 81                     if (color[e->e]==color[now] && !right[e->e])
 82                     {
 83                         right[e->e]=true;
 84                         q[++tail]=e->e;
 85                     }
 86             }
 87         }
 88     return true;
 89 }
 90 
 91 int main()
 92 {
 93     freopen("c.in","r",stdin);
 94     freopen("c.out","w",stdout);
 95 
 96     for (int a=1;a<=3;a++)
 97         for (int b=1;b<=3;b++)
 98         {
 99             add_edge(get(a,b,1),get(a,b,3));
100             add_edge(get(a,b,1),get(a,b,4));
101             add_edge(get(a,b,2),get(a,b,3));
102             add_edge(get(a,b,2),get(a,b,4));
103             if (a!=3) add_edge(get(a,b,2),get(a+1,b,1));
104             if (b!=3) add_edge(get(a,b,4),get(a,b+1,3));
105         }
106     int cnt=0;
107     for (int a=1;a<=3;a++)
108         for (int b=1;b<=3;b++)
109         {
110             scanf("%s",s+1);
111             for (int c=1;c<=4;c++)
112                 if (s[c]=='R') map[cnt][c]=0;
113                 else 
114                 {
115                     if (s[c]=='G') map[cnt][c]=1;
116                     else
117                     {
118                         if (s[c]=='B') map[cnt][c]=2;
119                         else map[cnt][c]=3;
120                     }
121                 }
122             if (s[5]=='1') row[a]=col[b]=true;
123             cnt++;
124         }
125     int nows=1234567;
126     if (check(nows))
127     {
128         printf("0\n");
129         return 0;
130     }
131     que.push(rec(nows,0));
132     use[nows]=true;
133     rec now;
134     while (que.size())
135     {
136         now=que.front();
137         que.pop();
138         int step=now.step;
139         int nows=now.sta;
140         memset(num,false,sizeof(num));
141         for (int a=3;a>=1;a--)
142             for (int b=3;b>=1;b--)
143                 if (a!=3 || b!=3)
144                 {
145                     nowmap[a][b]=nows%10;
146                     num[nows%10]=true;
147                     nows/=10;
148                 }
149         for (int a=0;a<9;a++)
150             if (!num[a])
151             {
152                 nowmap[3][3]=a;
153                 break;
154             }
155         int news=0;
156         for (int a=1;a<=3;a++)
157         {
158             if (!row[a])
159             {
160                 for (int b=1;b<=3;b++)
161                     for (int c=1;c<=3;c++)
162                         newmap[b][c]=nowmap[b][c];
163                 int x=newmap[a][1];
164                 newmap[a][1]=newmap[a][2];newmap[a][2]=newmap[a][3];newmap[a][3]=x;
165                 news=0;
166                 for (int b=1;b<=3;b++)
167                     for (int c=1;c<=3;c++)
168                         if (b!=3 || c!=3) news=news*10+newmap[b][c];
169                 if (!use[news])
170                 {
171                     use[news]=true;
172                     if (check(news))
173                     {
174                         printf("%d\n",step+1);
175                         return 0;
176                     }
177                     que.push(rec(news,step+1));
178                 }
179                 x=newmap[a][1];
180                 newmap[a][1]=newmap[a][2];newmap[a][2]=newmap[a][3];newmap[a][3]=x;
181                 news=0;
182                 for (int b=1;b<=3;b++)
183                     for (int c=1;c<=3;c++)
184                         if (b!=3 || c!=3) news=news*10+newmap[b][c];
185                 if (!use[news])
186                 {
187                     use[news]=true;
188                     if (check(news))
189                     {
190                         printf("%d\n",step+1);
191                         return 0;
192                     }
193                     que.push(rec(news,step+1));
194                 }
195             }
196             if (!col[a])
197             {
198                 for (int b=1;b<=3;b++)
199                     for (int c=1;c<=3;c++)
200                         newmap[b][c]=nowmap[b][c];
201                 int x=newmap[1][a];
202                 newmap[1][a]=newmap[2][a];newmap[2][a]=newmap[3][a];newmap[3][a]=x;
203                 news=0;
204                 for (int b=1;b<=3;b++)
205                     for (int c=1;c<=3;c++)
206                         if (b!=3 || c!=3) news=news*10+newmap[b][c];
207                 if (!use[news])
208                 {
209                     use[news]=true;
210                     if (check(news))
211                     {
212                         printf("%d\n",step+1);
213                         return 0;
214                     }
215                     que.push(rec(news,step+1));
216                 }
217                 x=newmap[1][a];
218                 newmap[1][a]=newmap[2][a];newmap[2][a]=newmap[3][a];newmap[3][a]=x;
219                 news=0;
220                 for (int b=1;b<=3;b++)
221                     for (int c=1;c<=3;c++)
222                         if (b!=3 || c!=3) news=news*10+newmap[b][c];
223                 if (!use[news])
224                 {
225                     use[news]=true;
226                     if (check(news))
227                     {
228                         printf("%d\n",step+1);
229                         return 0;
230                     }
231                     que.push(rec(news,step+1));
232                 }
233             }
234         }
235     }
236 
237     return 0;
238 }
c

 

posted @ 2017-10-01 20:56  baka  阅读(171)  评论(0编辑  收藏  举报