T1
【问题描述】
定义新字符串的权值计算方法。一个字符串由小写字母组成,字符串的权值被定义为其中出现次数最多的字符的次数减去出现次数最少的字符的次数。(注意,在讨论出现最少的字符的时候,该字符必须至少出现一次)现在给你一个字符串,这个字符串的所有子串中权值最大的权值是多少?
【输入格式】
第一行一个整数n,代表字符串的长度。
接下来一行n个小写字母,代表该字符串。
【输出格式】
一行一个整数代表答案。
【样例输入】
10
aabbaaabab
【样例输出】
3
【数据范围与规定】
对于30%的数据, 1 ≤n ≤ 100
对于60%的数据, 1 ≤ n ≤ 1000
对于100%的数据, 1 ≤ n ≤ 10^6
思路
先扔出来一组自造数据
10
aaabaaaaab
一开始做题直接懵那去了,样例能过但是过不了这个(其实能过,但是非常zz的以为这个答案是8而不是7.。。不知道当时的脑回路是怎么个构造)
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
using namespace std;
const int sz = 1000010;
const int size = 26;
const int N = 1500;
const int inf = 214748364;
#define ri register int
inline void rd(int &x){
x=0;bool f=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
if(f) x*=-1;
}
char fu[sz];
int n,t[sz],ans,num;
int ed[sz],f[N][N],dis[N][N];
inline int check(int x,int y){
return x==y;
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
rd(n);scanf("%s",fu+1);
for(ri i=1;i<=n;++i)
{
num=fu[i]-'a',t[num]++;
ed[num]=i;
for(ri j=0;j<size;++j)
{
if(j!=i&&t[j])
ans=max(ans,max
(t[num]-t[j]-check(ed[j],f[num][j])-dis[num][j],
t[j]-t[num]-check(ed[j],f[j][num])-dis[j][num]));
}
for(ri k=0;k<size;++k)
{
if(dis[num][k]>t[num]-t[k])
{
dis[num][k]=t[num]-t[k];
f[num][k]=i;
}
if(dis[k][num]>t[k]-t[num])
{
dis[k][num]=t[k]-t[num];
f[k][num]=i;
}
}
}
cout<<ans<<'\n';
fclose(stdin);
fclose(stdout);
return 0;
}
/*
10
aabbaaabab
*/
T2
【输出格式】
如果 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 的位置不同,且不在任何一条线段
上
思路
真是个,,,良心题目?输出YES有46分,NO则是54分(刷脸机?)自带数学与物理美感的题目emmmmm,以下分析用M代表镜子,W代表墙
我们考虑多种情况,首先我们将线段看成直线,两条直线分别代表墙和目光
这样对于右边的图来说,如果O为AB和CD交点,那么AB和CD想要避免相交就必须满足对于每一条线段的两端都要在交点的同侧才可以做到不相交,即到对方;而分隔在两侧是绝对看不到对方只能看墙的
这个判断我们可以做到先求出直线的方程(都是一次函数 y=kx+b)然后我们找斜率k的关系,判断求解
那么具体是如何做呢?如果两人在镜子同一侧,并且ST连线穿过了墙(不可能直接看到),我们需要对镜贴花黄【划掉划掉】研究下
根据美妙的数学和物理原理,我们做S对于M的对称点S’ 那么S’T的连线就是目光,可以理解为橙色的和红实线是目光,而红虚线是假象目光线(数学上经常用啊什么的)
设交点为P,那么分析如果墙在SP或PT直间那么就一定GG,看不到对方,因此我们可以狠狠地进行各种判断,暴力的分析模拟各种情况,以求得最终结果(不行不就随便rand或者输出嘛)
代码如下:
#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;
}
T3
【问题描述】
众所周知, 八数码问题是一个非常难的问题, 但把这道题简化一番。 现在给了你一个3 × 3的方格图, 你的目标是通过不断移动使得相邻颜色的块形成联通块。你每次的移动方式是选择一列或者一行进行置换滑动(这个解释起来比较麻烦, 看下面的图就懂了)。 所谓置换滑动, 就是所有格子沿着给定的方向顺次移动, 最后一个格子会被置换到最前面的过程。 现在给定整个方格图, 以及每个格子是否能够移动, 求使得相同颜色联通的最小步数。
【输入格式】
输入为3 × 3的方格图, 每个位置由五个字符组成, 前四个字符分别表示上下左右四个部分的颜色, 第五个字符表示该格子是否能够移动, 其中0是能移动1是不能移动。
【输出格式】
一行一个整数代表答案。
【样例输入】
GGGG0 GGGG0 GGGG0
OGOO0 GGGG0 OGOO0
OOOO0 OGGG1 OOOO0
【样例输出】
5
题解
暴力1:
真·暴力
什么判断都不加直接出样例——30
嗯,样例30
暴力2:
下面我们看看更加有深度的,额,暴力。。。。
炒鸡感谢zzy提供了第三题的解题情报
因为题目说明可以任意每行每列移动任意距离格子,那么对于每一个格子来说,它到任意一个地方在最优解下所耗费的步数不会超过2(步数<=2)
需要举个例子么?
例一:
右上角移到中间需要:下移一步,再左移一步
例二:
需要:下移一步然后右移(或者其他转移,最优情况下应该都是两步解决)
这样的话我们的最优化情况是多少次移动呢?
18次(因为每个格子都需要移动两步才能达到的话)
真的是18次么?
其实可以压缩到9次(每个格子移动时会替换掉另一个,当然,另一个也会去替换它或者别的格子,但是最终保持的都是每两个格子相对于原来的位置发生变换)
因此答案的范围大概就会限定在9步之内(这就是为什么puts(“5”);成功拿到30分的原因,太扎堆了)
真的是9次么?
它会给定不能移动的,而1步到位这样的数据估计不会给,而如果你八个格子全部移位到最优情况,那么剩下的那一个必定被迫最优化掉了,所以最坏情况是8种,如果出题人不很丧的话应该不会构造一个8的情况,因此我们的答案就在2~7中选择
因此如果我们搜索的话(emmmmmmm)每个格子的可能态有六种,
(2^6)^9
18014398509481984
嗯, 论述结束,下面开始扯正解吧emmm
正解?还没想出来啊w
先丢代码吧w
#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;
}