10.1综合强化刷题 Day1
a
【问题描述】
你是能看到第一题的 friends 呢。
——hja
何大爷对字符串十分有研究,于是天天出字符串题虐杀 zhx。何大爷今天为
字符串定义了新的权值计算方法。一个字符串由小写字母组成,字符串的权值
被定义为其中出现次数最多的字符的次数减去出现次数最少的字符的次数。 (注
意,在讨论出现最少的字符的时候,该字符必须至少出现一次)现在何大爷给
你一个字符串,何大爷想知道这个字符串的所有子串中权值最大的权值是多
少?
【输入格式】
第一行一个整数?,代表字符串的长度。
接下来一行?个小写字母,代表该字符串。
【输出格式】
一行一个整数代表答案。
【样例输入】
10
aabbaaabab
【样例输出】
3
【数据范围与规定】
3。
60%的数据,1 ≤ ? ≤ 1000。
对于100%的数据,1 ≤ ? ≤ 10 6 .
暴力枚举左右端点,然后每次更新这段区间内的最大值与最小值,然后相减,更新出最终答案
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 30 using namespace std; char ch[1100000]; int n,s[1100000][N],ans,minn,maxn; using namespace std; int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*f; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); n=read(); cin>>ch; for(int i=0;i<n;i++) for(int j=1;j<=26;j++) { if(ch[i]-'a'+1==j) s[i+1][j]=s[i][j]+1; else s[i+1][j]=s[i][j]; } for(int l=1;l<n;l++) for(int i=1;i<=n;i++) { maxn=0,minn=0x7fffffff; if(i+l>n) break; for(int j=1;j<=26;j++) { maxn=max(maxn,s[i+l][j]-s[i-1][j]); if(minn>s[i+l][j]-s[i][j]&&(s[i+l][j]-s[i-1][j])!=0) minn=s[i+l][j]-s[i-1][j]; } ans=max(ans,maxn-minn); } printf("%d",ans); }
我们可以看到数据范围为1<=n<=10^6,那么我们必须要将时间复杂度降的小一点,那么我们就来想办法把时间复杂度降到o(n*26)吧
我们选定一段区间l~r,我们假设出现次数最多的字母为x最少的为y,我们用一个数组sum统计一个字母到当前位置出现的次数,那么最多字母与最小字母的差值即为sum[x][r]-sum[x][l-1]-(sum[y][r]-sum[y][l-1])=sum[x][r]-sum[y][r]-sum[x][l-1]+sum[y][l-1]=sum[x][r]-sum[y][r]-(sum[x][l-1]-sum[y][l-1])我们可以发现前面的部分跟后面的部分是一样的,并且我们sum数组的l-1一定是在r之前,也就是说我们的l-1可以再r之前就被处理出来。那么现在我们需要知道的就只有x和y到底是谁了,我们枚举每一个点,然后在枚举另一个字母,处理出最大的sum[x][r]-sum[y][r],这个r就是我们要枚举的位置,x为这个位置上的字母,y为枚举的另一个字母,我们更新最大值,这样的话我们枚举出来的字母有两种情况,要么x比y多,要么y比x多,我们取一个最大值来更新答案,我们这里的sum[x][l-1]-sum[y][l-1]是前面处理出来的,每次在枚举到的位置去一最小值储存一下,我们还要统计是在什么时候更新的这个最小值,当这个位置跟我们枚举的另一个字母的位置相同我们还要减去1,为重叠的那个字母。
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 30 using namespace std; char ch[1000001]; int n,now,ans,sum[N],pos[N][N],last[N],minn[N][N]; int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*f; } int main() { n=read(); cin>>ch+1; for(int i=1;i<=n;i++) { now=ch[i]-'a'; last[now]=i; sum[now]++; for(int j=0;j<26;j++) if(now!=j&&sum[j]) ans=max(ans,max(sum[now]-sum[j]-minn[now][j]-(last[j]==pos[now][j]), sum[j]-sum[now]-minn[j][now]-(last[j]==pos[j][now]))); for(int j=0;j<26;j++) { if(sum[now]-sum[j]<minn[now][j]) minn[now][j]=sum[now]-sum[j],pos[now][j]=i; if(sum[j]-sum[now]<minn[j][now]) minn[j][now]=sum[j]-sum[now],pos[j][now]=i; } } printf("%d",ans); return 0; }
b
【问题描述】
如果视线和障碍物有公共点,那么我们认为视线会被阻挡,无法看见。如果
视线和镜子有公共点,那么我们认为发生了反射。反射的过程遵循物理规律——
入射角等于反射角,且反射光线与入射光线在镜子同侧。也就是说,想要看见对
方,Hja 和 Yjq 必须在镜子的同一侧,包括镜子所在直线上(参见样例 1) 。如果
视线与镜子重合, 那么不会发生反射, 并且镜子不被当作障碍物 (参见样例 4) 。
Hja 很想知道他站在原地能否看见 Yjq,帮助他解决这个问题。
【输入格式】
【输出格式】
如果 Hja 站在原地能看到 Yjq,则输出"YES",否则输出"NO"。
【样例输入 1】
-1 3
1 3
0 2 0 4
0 0 0 1
【样例输出 1】
NO
【样例输入 2】
0 0
1 1
0 1 1 0
-100 -100 -101 -101
【样例输出 2】
NO
【样例输入 3】
0 0
1 1
0 1 1 0
-1 1 1 3
【样例输出 3】
YES
【样例输入 4】
0 0
10 0
100 100 101 101
1 0 3 0
【样例输出 4】
YES
【数据规模与约定】
对于100%的数据,所有坐标均为绝对值不超过10 4 的整数。输入的线段不会
退化成点,且两条线段没有交点。Hja 和 Yjq 的位置不同,且不在任何一条线段
上。
zz的数据,输出yes能得46分、、、
解析几何
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const double eps=1e-8; int sgn(double a) { if (fabs(a)<eps) return 0; else { if (a>0.0) return 1; else return -1; } } struct point { double x,y; point(){} point(double a,double b) { x=a;y=b; } void init() { scanf("%lf%lf",&x,&y); } point operator+(const point &a)const { point ans; ans.x=x+a.x; ans.y=y+a.y; return ans; } point operator-(const point &a)const { point ans; ans.x=x-a.x; ans.y=y-a.y; return ans; } point operator*(const double &a)const { point ans; ans.x=x*a; ans.y=y*a; return ans; } void print() { printf("%lf %lf\n",x,y); } }v,p,w1,w2,m1,m2; double cross(point a,point b) { return a.x*b.y-a.y*b.x; } double dot(point a,point b) { return a.x*b.x+a.y*b.y; } bool cross(point p1,point p2,point p3,point p4) { if (sgn(cross(p2-p1,p3-p1))*sgn(cross(p2-p1,p4-p1))==1) return false; if (sgn(cross(p4-p3,p1-p3))*sgn(cross(p4-p3,p2-p3))==1) return false; if (sgn(max(p1.x,p2.x)-min(p3.x,p4.x))==-1) return false; if (sgn(max(p1.y,p2.y)-min(p3.y,p4.y))==-1) return false; if (sgn(max(p3.x,p4.x)-min(p1.x,p2.x))==-1) return false; if (sgn(max(p3.y,p4.y)-min(p1.y,p2.y))==-1) return false; return true; } point getcross(point p1,point p2,point p3,point p4) { double a=p2.y-p1.y; double b=p1.x-p2.x; double c=-p1.x*p2.y+p1.y*p2.x; double d=p4.y-p3.y; double e=p3.x-p4.x; double f=-p3.x*p4.y+p3.y*p4.x; double x=(b*f-c*e)/(a*e-b*d); double y=(a*f-c*d)/(b*d-a*e); return point(x,y); } point calcfoot(point p1,point p2,point p3) { double ratio=dot(p1-p2,p3-p2)/dot(p3-p2,p3-p2); return p2+(p3-p2)*ratio; } bool check() { if (!cross(v,p,w1,w2)) { if (!cross(v,p,m1,m2)) return true; if (sgn(cross(m1-v,m2-v))==0 && sgn(cross(m1-p,m2-p)==0)) return true; } if (sgn(cross(m2-m1,v-m1))*sgn(cross(m2-m1,p-m1))==1) { point foot=calcfoot(p,m1,m2); foot=foot*2.0-p; if (cross(v,foot,m1,m2)) { foot=getcross(v,foot,m1,m2); if (!cross(v,foot,w1,w2) && !cross(foot,p,w1,w2)) return true; } } return false; } int main() { freopen("b.in","r",stdin); freopen("b.out","w",stdout); v.init(); p.init(); w1.init(); w2.init(); m1.init(); m2.init(); if (check()) printf("YES\n"); else printf("NO\n"); return 0; }
c
【问题描述】
你是能看到第三题的 friends 呢。
——aoao
众所周知,八数码问题是一个非常难的问题,但是 Yjq 非常有面子,他把这
道题简化了一番。 现在给了你一个3 × 3的方格图, 你的目标是通过不断移动使得
相邻颜色的块形成联通块。 你每次的移动方式是选择一列或者一行进行置换滑动
(这个解释起来比较麻烦,看下面的图就懂了) 。所谓置换滑动,就是所有格子
沿着给定的方向顺次移动, 最后一个格子会被置换到最前面的过程。 现在给定整
个方格图,以及每个格子是否能够移动,求使得相同颜色联通的最小步数。
【输入格式】
输入为3 × 3的方格图,每个位置由五个字符组成,前四个字符分别表示上下
左右四个部分的颜色, 第五个字符表示该格子是否能够移动, 其中0是能移动1是
不能移动。
【输出格式】
一行一个整数代表答案。
【样例输入】
GGGG0 GGGG0 GGGG0
OGOO0 GGGG0 OGOO0
OOOO0 OGGG1 OOOO0
【样例输出】
5
【样例解释】
【数据规模与约定】
对于100%的数据,所有颜色只可能是 RGBO 中的一种,且一定有解。
变态的搜索
#include<cstdio> #include<cstdlib> #include<cstring> #include<queue> using namespace std; #define get(a,b,c) ((a-1)*12+(b-1)*4+c) int en,tmp[4][4],color[37],map[9][5],q[37],nowmap[4][4],newmap[4][4]; bool num[9],use[90000000],right[37],row[4],col[4],col_find[5]; char s[10]; struct rec { int sta,step; rec(){} rec(int a,int b) { sta=a;step=b; } }; queue<rec> que; struct edge { int e; edge *next; }*v[37],ed[100]; void add_edge(int s,int e) { en++; ed[en].next=v[s];v[s]=ed+en;v[s]->e=e; en++; ed[en].next=v[e];v[e]=ed+en;v[e]->e=s; } bool check(int nows) { memset(num,false,sizeof(num)); for (int a=3;a>=1;a--) for (int b=3;b>=1;b--) if (a!=3 || b!=3) { tmp[a][b]=nows%10; num[nows%10]=true; nows/=10; } for (int a=0;a<9;a++) if (!num[a]) { tmp[3][3]=a; break; } int cnt=0; for (int a=1;a<=3;a++) for (int b=1;b<=3;b++) for (int c=1;c<=4;c++) { cnt++; color[cnt]=map[tmp[a][b]][c]; } memset(right,false,sizeof(right)); memset(col_find,false,sizeof(col_find)); for (int a=1;a<=36;a++) if (!right[a]) { if (col_find[color[a]]) return false; col_find[color[a]]=true; int front=1,tail=1; q[1]=a; right[a]=true; for (;front<=tail;) { int now=q[front++]; for (edge *e=v[now];e;e=e->next) if (color[e->e]==color[now] && !right[e->e]) { right[e->e]=true; q[++tail]=e->e; } } } return true; } int main() { freopen("c.in","r",stdin); freopen("c.out","w",stdout); for (int a=1;a<=3;a++) for (int b=1;b<=3;b++) { add_edge(get(a,b,1),get(a,b,3)); add_edge(get(a,b,1),get(a,b,4)); add_edge(get(a,b,2),get(a,b,3)); add_edge(get(a,b,2),get(a,b,4)); if (a!=3) add_edge(get(a,b,2),get(a+1,b,1)); if (b!=3) add_edge(get(a,b,4),get(a,b+1,3)); } int cnt=0; for (int a=1;a<=3;a++) for (int b=1;b<=3;b++) { scanf("%s",s+1); for (int c=1;c<=4;c++) if (s[c]=='R') map[cnt][c]=0; else { if (s[c]=='G') map[cnt][c]=1; else { if (s[c]=='B') map[cnt][c]=2; else map[cnt][c]=3; } } if (s[5]=='1') row[a]=col[b]=true; cnt++; } int nows=1234567; if (check(nows)) { printf("0\n"); return 0; } que.push(rec(nows,0)); use[nows]=true; rec now; while (que.size()) { now=que.front(); que.pop(); int step=now.step; int nows=now.sta; memset(num,false,sizeof(num)); for (int a=3;a>=1;a--) for (int b=3;b>=1;b--) if (a!=3 || b!=3) { nowmap[a][b]=nows%10; num[nows%10]=true; nows/=10; } for (int a=0;a<9;a++) if (!num[a]) { nowmap[3][3]=a; break; } int news=0; for (int a=1;a<=3;a++) { if (!row[a]) { for (int b=1;b<=3;b++) for (int c=1;c<=3;c++) newmap[b][c]=nowmap[b][c]; int x=newmap[a][1]; newmap[a][1]=newmap[a][2];newmap[a][2]=newmap[a][3];newmap[a][3]=x; news=0; for (int b=1;b<=3;b++) for (int c=1;c<=3;c++) if (b!=3 || c!=3) news=news*10+newmap[b][c]; if (!use[news]) { use[news]=true; if (check(news)) { printf("%d\n",step+1); return 0; } que.push(rec(news,step+1)); } x=newmap[a][1]; newmap[a][1]=newmap[a][2];newmap[a][2]=newmap[a][3];newmap[a][3]=x; news=0; for (int b=1;b<=3;b++) for (int c=1;c<=3;c++) if (b!=3 || c!=3) news=news*10+newmap[b][c]; if (!use[news]) { use[news]=true; if (check(news)) { printf("%d\n",step+1); return 0; } que.push(rec(news,step+1)); } } if (!col[a]) { for (int b=1;b<=3;b++) for (int c=1;c<=3;c++) newmap[b][c]=nowmap[b][c]; int x=newmap[1][a]; newmap[1][a]=newmap[2][a];newmap[2][a]=newmap[3][a];newmap[3][a]=x; news=0; for (int b=1;b<=3;b++) for (int c=1;c<=3;c++) if (b!=3 || c!=3) news=news*10+newmap[b][c]; if (!use[news]) { use[news]=true; if (check(news)) { printf("%d\n",step+1); return 0; } que.push(rec(news,step+1)); } x=newmap[1][a]; newmap[1][a]=newmap[2][a];newmap[2][a]=newmap[3][a];newmap[3][a]=x; news=0; for (int b=1;b<=3;b++) for (int c=1;c<=3;c++) if (b!=3 || c!=3) news=news*10+newmap[b][c]; if (!use[news]) { use[news]=true; if (check(news)) { printf("%d\n",step+1); return 0; } que.push(rec(news,step+1)); } } } } return 0; }