1.a(a.cpp/c/pas)
时间限制
1000ms
空间限制
256MB
【问题描述】
你是能看到第一题的 friends呢。 —— hja
何大爷对字符串十分有研究,于是天出题虐杀 zhx。何大爷今天为字符串定义了新的权值计算方法。一个字符串由小写字母组成,字符串的权值被定义为其中出现次数最多的字符的次数减去少出现次数最少的字符的次数。(注 被定义为其中出现次数最多的字符减去少。(注意,在讨论出现最少的字符的时候该字符必须至少出现一次)现在何大爷给你一个字符串,何大爷想知道这个字符串的所有子串中权值最大的权值是多少?
【输入格式】
第一行 一个整数
n
,代表字符串的长度 。
接下来一行
【输出格式】
一行个整数代表答案。
【样例输入】
10
aabbaaabab
【样例输出】
3
【数据范围与规定】
对于
30%
的数据,
1≤n≤100
对于
60%
的数据,
1≤n≤1000
对于
100%
的数据,
1≤n≤106
solution
60分
- 暴力枚举每个字串,对于每个字串更新一次答案。
100分
令 sum[c][i] 表示 c 这个字符到
i 这个位置出现的次数l 表示子串的左端点,
r 表示右端点那对于一个子串他的权值就是 max{sum[c][r]−sum[c][l−1]}−min{sum[c][r]−sum[c][l−1]} ,其中 c 是小写字母
假设在每个子串中出现次数最多的那个字符为
a ,最小的为 b那
ans=sum[a][r]−sum[a][l−1]−(sum[b][r]−sum[b][l−1]) =sum[a][r]−sum[b][r]+sum[b][l−1]−sum[a][l−1]
=sum[a][r]−sum[b][r]−(sum[a][l−1]−sum[b][l−1])
计算上面那个式子的 max ,需要枚举两个字符 a,b 和两个端点 l,r
时间复杂度是 O(n2∗262) ,会 TLE
先把 262 优化到 26
每次移动端点仅仅是新加入一个字符,也就是说只有这一个新加入的字符会影响答案,所以只用这个字符和其余的字符做差然后取绝对值就好了,并不用挨个枚举更新答案
然后再把 n2 优化到 n
因为对于最后的答案我们并不在意
l,r ,所以看一下能不能省掉一维状态对于每次右端点的移动,可能它对应的最右的左端点和上次一样
也就是说右端点的移动不一定会让 (sum[a][l−1]−sum[b][l−1]) 的最小值更新
所以用一个数组 Min[a][b] 来保存 (sum[a][l−1]−sum[b][l−1]) 的最小值
然后 sum 数组直接省掉第二维,表示的是到当前右端点字符出现的次数之和
假设出现在右端点的字符是 a ,其余的字母是
b ,那么每次移动右端点ans=max{sum[a]−sum[b]−Min[a][b],sum[b]−sum[a]−Min[b][a]}
这样来更新还是有BUG的,你还需要记录最后更新 Min[a][b] 的位置和 b 最后出现的位置
如果这两个位置相同,
sum[a]−sum[b]−Min[a][b] 的值还要再 −1这个东西很好想的,自己想一下就可以想出来,我就不再赘述啦
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 1000010
int sum[30],last[30];
int Min[30][30],pos[30][30];
char s[MAXN];
int main() {
int n;
scanf("%d%s",&n,s+1);
int ans=-1;
for(int i=1;i<=n;i++) {
int a=s[i]-'a'+1;
sum[a]++;
last[a]=i;
for(int b=1;b<=26;b++)
if(b!=a&&sum[b]!=0) {
ans=max(ans,sum[a]-sum[b]-Min[a][b]-(last[b]==pos[a][b]));
ans=max(ans,sum[b]-sum[a]-Min[b][a]-(last[b]==pos[b][a]));
}
for(int b=1;b<=26;b++) {
if(sum[a]-sum[b]<Min[a][b]) {
Min[a][b]=sum[a]-sum[b];
pos[a][b]=i;
}
if(sum[b]-sum[a]<Min[b][a]) {
Min[b][a]=sum[b]-sum[a];
pos[b][a]=i;
}
}
}
printf("%d",ans);
return 0;
}
2.b(b.cpp/c/pas)
时间限制
1000ms
空间限制
256MB
【问题描述】
你是能看到第二题的 friends 呢。 ——laekov
Hja 和 Yjq 在玩捉迷藏。Yjq 躲了起来,Hja 要找他。在他们玩游戏的房间里,只有一堵不透明的墙和一个双面的镜子。Hja 和 Yjq 可以看作平面上坐标分别为 (Xv,Yv) 和 (Xp,Yp) 的点。墙是一条连接 (Xw1,Yw1) 和 (Xw2,Yw2) 的线段,镜子是一条连接 (Xm1,Ym1) 和 (Xm2,Ym2) 的线段。
如果视线和障碍物有公共点,那么我们认为视线会被阻挡,无法看见。如果视线和镜子有公共点,那么我们认为发生了反射。反射的过程遵循物理规律——入射角等于反射角,且反射光线与入射光线在镜子同侧。也就是说,想要看见对方,Hja 和 Yjq 必须在镜子的同一侧,包括镜子所在直线上(参见样例 1)。如果视线与镜子重合,那么不会发生反射,并且镜子不被当作障碍物(参见样例 4)。
Hja 很想知道他站在原地能否看见 Yjq,帮助他解决这个问题。
【输入格式】
第一行两个数
Xv,Yv
,表示 Hja 的坐标。
第二行两个数
Xp,Yp
表示 Yjq 的坐标。
第三行四个数
Xw1,Yw1,Xw2,Yw2
,分别表示墙的两个端点的坐标。
第四行四个数
Xm1,Ym1,Xm2,Ym2
,分别表示镜子的两个端点的坐标。
【输出格式】
如果 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% 的数据,所有坐标均为绝对值不超过 104 的整数。输入的线段不会退化成点,且两条线段没有交点。Hja 和 Yjq 的位置不同,且不在任何一条线段上。
solution
hja只有在两种情况下可以看见yjq
不需要镜子就可以直接看见yjq
- 直接看视线被墙挡住,但可以通过镜子看见
所以就可以先判断能否直接看见,在判断可不可以通过镜子看见
不能通过镜子看见有三种情况
入射光线被墙挡住
- 反射光线被墙挡住
- 两个人不在镜子的同一侧
还有就是要注意题目中说的一些特殊情况
这种情况也可以看见
算是一道计算几何入门题目
code
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const double eps=1e-8;
int sgn(double x) {
if(fabs(x)<eps) return 0;
if(x>0.00) return 1;
return -1;
}
struct Point {
double x,y;
Point(double x=0.00,double y=0.00):
x(x),y(y) {}
void SCANF() {
scanf("%lf%lf",&x,&y);
return;
}
Point operator + (const Point &q) const {
return Point(x+q.x,y+q.y);;
}
Point operator - (const Point &q) const {
return Point(x-q.x,y-q.y);
}
Point operator * (const double &q) const {
return Point(x*q,y*q);
}
};
Point hja,yjq,w1,w2,m1,m2;
double cross(Point a,Point b) {
return a.x*b.y-b.x*a.y;
}
double dot(Point a,Point b) {
return a.x*b.x+a.y*b.y;
}
double 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 calc_foot(Point p1,Point p2,Point p3) {
double ratio=dot(p1-p2,p3-p2)/dot(p3-p2,p3-p2);
return p2+(p3-p2)*ratio;
}
bool Judge() {
if(!cross(hja,yjq,w1,w2)) {
if(!cross(hja,yjq,m1,m2)) return true;
if(!sgn(cross(m1-hja,m2-hja))&&!sgn(cross(m1-yjq,m2-yjq)))
return true;
}
if(sgn(cross(m2-m1,hja-m1))*sgn(cross(m2-m1,yjq-m1))==1) {
Point foot=calc_foot(yjq,m1,m2);
foot=foot*2.0-yjq;
if(cross(hja,foot,m1,m2)) {
foot=GetCross(hja,foot,m1,m2);
if(!cross(hja,foot,w1,w2)&&!cross(foot,yjq,w1,w2))
return true;
}
}
return false;
}
int main() {
hja.SCANF(),yjq.SCANF();
w1.SCANF(),w2.SCANF();
m1.SCANF(),m2.SCANF();
puts(Judge()?"YES":"NO");
return 0;
}
3.c(c.cpp/c/pas)
时间限制
1000ms
空间限制
256MB
【问题描述】
你是能看到第三题的 friends 呢。——aoao
众所周知,八数码问题是一个非常难的问题,但是 Yjq 非常有面子,他把这道题简化了一番。现在给了你一个3 × 3的方格图,你的目标是通过不断移动使得相邻颜色的块形成联通块。你每次的移动方式是选择一列或者一行进行置换滑动(这个解释起来比较麻烦,看下面的图就懂了)。所谓置换滑动,就是所有格子沿着给定的方向顺次移动,最后一个格子会被置换到最前面的过程。现在给定整个方格图,以及每个格子是否能够移动,求使得相同颜色联通的最小步数。
【输入格式】
输入为3 × 3的方格图,每个位置由五个字符组成,前四个字符分别表示上下
左右四个部分的颜色,第五个字符表示该格子是否能够移动,其中
0
是能移动
不能移动。
【输出格式】
一行一个整数代表答案。
【样例输入】
GGGG0 GGGG0 GGGG0
OGOO0 GGGG0 OGOO0
OOOO0 OGGG1 OOOO0
【样例输出】
5
【样例解释】
【数据规模与约定】
对于 100% 的数据,所有颜色只可能是 RGBO 中的一种,且一定有解。
solution
- 因为每个格子都包含4个三角形,所以直接把一个格子看成4个点然后建图
- 然后就是爆搜,zhx:爆搜真的没什么好讲的.
code
200+行一点也不长呢
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Edge {
int u,v,next;
Edge(int u=0,int v=0,int next=0):
u(u),v(v),next(next) {}
};
Edge edge[110];
int head[50],cnt;
void addedge(int u,int v) {
edge[++cnt]=Edge(u,v,head[u]);
head[u]=cnt;
edge[++cnt]=Edge(v,u,head[v]);
head[v]=cnt;
return;
}
struct rec {
int s,step;
rec(int s=0,int step=0):
s(s),step(step) {}
};
int tmp[5][5],color[50];
int Map[10][5];
int nowmap[5][5],newmap[5][5];
bool num[10],use[87654325];
bool vis[50],col_find[5];
bool col[5],row[5];
char ch[10];
queue<int> q;
bool Judge(int now_s) {
memset(num,false,sizeof(num));
for(int i=3;i>=1;i--)
for(int j=3;j>=1;j--)
if(i!=3||j!=3) {
tmp[i][j]=now_s%10;
num[now_s%10]=true;
now_s/=10;
}
for(int i=0;i<9;i++)
if(!num[i]) {
tmp[3][3]=i;
break;
}
int Count=0;
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
for(int k=1;k<=4;k++)
color[++Count]=Map[tmp[i][j]][k];
memset(vis,false,sizeof(vis));
memset(col_find,false,sizeof(col_find));
for(int i=1;i<=36;i++)
if(!vis[i]) {
if(col_find[color[i]])
return false;
col_find[color[i]]=true;
for(;!q.empty();q.pop());
q.push(i);
vis[i]=true;
while(!q.empty()) {
int u=q.front();
q.pop();
for(int j=head[u];j;j=edge[j].next) {
int v=edge[j].v;
if(color[v]==color[u]&&!vis[v]) {
vis[v]=true;
q.push(v);
}
}
}
}
return true;
}
queue<rec> Q;
int bfs(int now_s) {
int step=0;
rec now=rec(now_s,0);
Q.push(now);
use[now_s]=true;
while(!Q.empty()) {
now=Q.front();
Q.pop();
now_s=now.s;
step=now.step;
memset(num,false,sizeof(num));
for(int i=3;i>=1;i--)
for(int j=3;j>=1;j--)
if(i!=3||j!=3) {
nowmap[i][j]=now_s%10;
num[now_s%10]=true;
now_s/=10;
}
for(int i=0;i<9;i++)
if(!num[i]) {
nowmap[3][3]=i;
break;
}
int new_s,T;
for(int i=1;i<=3;i++) {
if(!row[i]) {
for(int j=1;j<=3;j++)
for(int k=1;k<=3;k++)
newmap[j][k]=nowmap[j][k];
T=newmap[i][1];
newmap[i][1]=newmap[i][2];
newmap[i][2]=newmap[i][3];
newmap[i][3]=T;
new_s=0;
for(int j=1;j<=3;j++)
for(int k=1;k<=3;k++)
if(j!=3||k!=3)
new_s=new_s*10+newmap[j][k];
if(!use[new_s]) {
use[new_s]=true;
if(Judge(new_s)) return step+1;
Q.push(rec(new_s,step+1));
}
T=newmap[i][1];
newmap[i][1]=newmap[i][2];
newmap[i][2]=newmap[i][3];
newmap[i][3]=T;
new_s=0;
for(int j=1;j<=3;j++)
for(int k=1;k<=3;k++)
if(j!=3||k!=3)
new_s=new_s*10+newmap[j][k];
if(!use[new_s]) {
use[new_s]=true;
if(Judge(new_s)) return step+1;
Q.push(rec(new_s,step+1));
}
}
if(!col[i]) {
for(int j=1;j<=3;j++)
for(int k=1;k<=3;k++)
newmap[j][k]=nowmap[j][k];
T=newmap[1][i];
newmap[1][i]=newmap[2][i];
newmap[2][i]=newmap[3][i];
newmap[3][i]=T;
new_s=0;
for(int j=1;j<=3;j++)
for(int k=1;k<=3;k++)
if(j!=3||k!=3)
new_s=new_s*10+newmap[j][k];
if(!use[new_s]) {
use[new_s]=true;
if(Judge(new_s)) return step+1;
Q.push(rec(new_s,step+1));
}
T=newmap[1][i];
newmap[1][i]=newmap[2][i];
newmap[2][i]=newmap[3][i];
newmap[3][i]=T;
new_s=0;
for(int j=1;j<=3;j++)
for(int k=1;k<=3;k++)
if(j!=3||k!=3)
new_s=new_s*10+newmap[j][k];
if(!use[new_s]) {
use[new_s]=true;
if(Judge(new_s)) return step+1;
Q.push(rec(new_s,step+1));
}
}
}
}
return 0;
}
#define id(i,j,k) ((i-1)*12+(j-1)*4+k)
int main() {
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++) {
addedge(id(i,j,1),id(i,j,3));
addedge(id(i,j,1),id(i,j,4));
addedge(id(i,j,2),id(i,j,3));
addedge(id(i,j,2),id(i,j,4));
if(i!=3) addedge(id(i,j,2),id(i+1,j,1));
if(j!=3) addedge(id(i,j,4),id(i,j+1,3));
}
int Count=0;
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++) {
scanf("%s",ch+1);
for(int k=1;k<=4;k++)
if(ch[k]=='R') Map[Count][k]=0;
else if(ch[k]=='G') Map[Count][k]=1;
else if(ch[k]=='B') Map[Count][k]=2;
else Map[Count][k]=3;
if(ch[5]=='1') row[i]=col[j]=true;
Count++;
}
int now_s=1234567;
if(Judge(now_s)) {
puts("0\n");
return 0;
}
printf("%d\n",bfs(now_s));
return 0;
}