2017.10.1北京清北综合强化班DAY1

Posted 小时のblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017.10.1北京清北综合强化班DAY1相关的知识,希望对你有一定的参考价值。


a
【问题描述】
你是能看到第一题的 friends 呢。
——hja
何大爷对字符串十分有研究,于是天天出字符串题虐杀 zhx。

何大爷今天为符串定义了新的权值计算方法。一个字符串

由小写字母组成,字符串的权值被定义为其中出现次数最多

的字符的次数减去出现次数最少的字符的次数。 (注意,在

讨论出现最少的字符的时候,该字符必须至少出现一次)现在

何大爷给你一个字符串,何大爷想知道这个字符串的所有子串

中权值最大的权值是多少?

【输入格式】
第一行一个整数?,代表字符串的长度。
接下来一行?个小写字母,代表该字符串。
【输出格式】
一行一个整数代表答案。
【样例输入】
10
aabbaaabab
【样例输出】
3
【数据范围与规定】
3。
60%的数据,1 ≤ ? ≤ 1000。
对于100%的数据,1 ≤ ? ≤ 10 6 .

 

题目大意:

求一个字符串子串的最多出现次数-最少出现次数的最大值。

题解:

30分做法O(n^3)枚举区间 扫最大最小值

60分做法O(26n^2)枚举区间 前缀和求最大最小值

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int n,maxx,minn,ans,sum[1020][26];
char s[1020];
int main(){
    scanf("%d",&n);scanf("%s",s+1);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=26;j++)sum[i][j]=sum[i-1][j];
        int z=s[i]-\'a\'+1;
        sum[i][z]=sum[i-1][z]+1;
    }
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
            if(i==j){
                ans=max(ans,0);
                continue;
            }
            maxx=-1;minn=100000;
            for(int k=1;k<=26;k++){
                int z=sum[j][k]-sum[i-1][k];
                if(z)minn=min(minn,z);
                maxx=max(maxx,z);
            }
            ans=max(ans,maxx-minn);
        }
    }
    printf("%d\\n",ans);
    return 0;
}
60分

 

枚举右端点,前缀和优化。对于当前点x,答案为

sum[x][r]-sum[x][l-1]-(sum[z][r]-sum[z][l-1])

整理为

sum[x][r]-sum[z][r]-(sum[x][l-1]-sum[z][l-1])

我们已知x和sum[x][r],对于z我们枚举,

对于sum[x][l-1]-sum[z][l-1]我们需要一个最小的

用minv[x][y]表示sum[x]-sum[y]的最小值。

 

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>

using namespace std;

const int maxn=1000010;

int n,ans,p[26][26],minv[26][26],sum[26],last[26];

char s[maxn];

int main()
{
    scanf("%d",&n);
    scanf("%s",s+1);
    for (int a=1;a<=n;a++)
    {
        int c=s[a]-\'a\';
        sum[c]++;
        last[c]=a;
        for (int b=0;b<26;b++)
            if (b!=c && sum[b]) ans=max(ans,max(sum[c]-sum[b]-minv[c][b]-(last[b]==p[c][b]),sum[b]-sum[c]-minv[b][c]-(last[b]==p[b][c])));
        for (int b=0;b<26;b++)
        {
            if (sum[c]-sum[b]<minv[c][b]) minv[c][b]=sum[c]-sum[b],p[c][b]=a;
            if (sum[b]-sum[c]<minv[b][c]) minv[b][c]=sum[b]-sum[c],p[b][c]=a;
        }
    }
    printf("%d\\n",ans);

    return 0;
}
AC

 

 

如果视线和障碍物有公共点,那么我们认为视线会被阻挡,无法看见。

如果视线和镜子有公共点,那么我们认为发生了反射。反射的过程遵

循物理规律——入射角等于反射角,且反射光线与入射光线在镜子同

侧。也就是说,想要看见对方,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 的位置不同,且不在任何一条线段上。

 

题解:计算几何 弃疗

代码:

#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;
}
AC

 

 

c
【问题描述】
你是能看到第三题的 friends 呢。
——aoao
众所周知,八数码问题是一个非常难的问题,但是Yjq 非常有

面子,他把这道题简化了一番。 现在给了你一个3 × 3的方格

图, 你的目标是通过不断移动使得相邻颜色的块形成联通块。

你每次的移动方式是选择一列或者一行进行置换滑动

(这个解释起来比较麻烦,看下面的图就懂了) 。所谓置换滑动,

就是所有格子沿着给定的方向顺次移动, 最后一个格子会被置换

到最前面的过程。 现在给定整个方格图,以及每个格子是否能够

移动,求使得相同颜色联通的最小步数。

【输入格式】
输入为3 × 3的方格图,每个位置由五个字符组成,前四个字符分别

表示上下左右四个部分的颜色, 第五个字符表示该格子是否能够移

动, 其中0是能移动1是不能移动。

【输出格式】
一行一个整数代表答案。

 

题解:爆搜

#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;
}
AC

 

以上是关于2017.10.1北京清北综合强化班DAY1的主要内容,如果未能解决你的问题,请参考以下文章

北京清北 综合强化班 Day1

北京清北 综合强化班 Day5

北京清北 综合强化班 Day2 T1

北京清北 综合强化班 Day3

北京清北 综合强化班 Day4 T1

2017.10.3北京清北综合强化班DAY3