北京信息科技大学第11届程序设计基本技能比赛

北京信息科技大学第11届程序设计基本技能比赛

A. 太阳花田

​ 题意:一个圆和一个长为x,高为y的矩形最大交集是多少?

​ 题解:分类讨论,显然四种情况,不妨假设x是短边。第一种,圆被矩形完全包含,(r<x/2),答案是圆的面积。第二种,圆露出去了两边(r<y/2),这里可以一个圆减去一个扇形,但是要加回来两个三角形,三角形的部分是简单三角函数计算。第三种就是露出去四个部分(r<sqrt(x/2*x/2+y/2*y/2)),同样是减去四个扇形,加回来四个三角形。最后一种情况,全部包含。

#include <bits/stdc++.h> //万能头

double x, y, r;

const double pi = acos(-1.0); //高精度pi

using namespace std;

int main(){
    cin>>x>>y>>r;
    if(y<x)swap(x,y);

    if(r<=x/2){
        printf("%.2f",pi*r*r);
    }else if (r<y/2){
        double ang = 2*acos(0.5*x/r);
        double l = ang*r;
        double s = l*r;
        s-=x*tan(ang/2)*x/2;
        printf("%.2f",pi*r*r-s);
    }else if(r*r<(x/2)*(x/2)+(y/2)*(y/2)){
        double ang=2*acos(0.5*x/r);
        double l=ang*r;
        double s=l*r;
        s-=x*tan(ang/2)*x/2;

        double ang1=2*acos(0.5*y/r);
        double l1=ang1*r;
        double s1=l1*r;
        s1-=y*tan(ang1/2)*y/2;
        printf("%.2f",pi*r*r-s-s1);
    }else{
        printf("%.2f",x*y);
    }

    return 0;
}

B. 算数教室

​ 题意:给两个长度为n的数组,是否存在两个下标a[i]+b[j]=target。

​ 题解:set存一下a[i],对b中每一个元素,查询一下set中是否有target-b[i]即可(即查询是否存在b[j]=target-a[i]),这样复杂度能够接受。

#include<bits/stdc++.h>

using namespace std;

int n, m, x;

set<int> S;

int main(){
    scanf("%d%d%d",&n,&m,&x);

    for(int i=1;i<=n;++i)S.insert(x);
    for(int i=1;i<=m;++i){
        int t;scanf("%d",&t);
        if(S.count(x-t)){
            cout<<"YES";
            return 0;
        }
    }
    cout<<"NO";

    return 0;
}

C. 博丽神社

​ 题意:过原点的直线有多少条,能使得所有的点与关于这条之间对称。

​ 题解:检查过每个点,和每两个点之间的中垂线。去重可以用pair<int,int>。这表示一个方向向量,细节看代码。

#include<bits/stdc++.h>

#define all(x) x.begin(),x.end()
#define fi first
#define sd second
#define lson (nd<<1)
#define rson (nd+nd+1)
#define PB push_back
#define mid (l+r>>1)
#define MP make_pair
#define SZ(x) (int)x.size()

using namespace std;

typedef long long LL;

typedef vector<int> VI;

typedef pair<int,int> PII;

inline int read(){
    int res=0, f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
    return res*f;
}

const int N = 105;

const int MOD = 1000000007;

template<typename T>
void chmin(T& a, T b){if(a>b)a=b;}

template<typename T>
void chmax(T& a, T b){if(b>a)a=b;}

int n;

struct point{
    int x, y;
    point(){}
    point(int _x, int _y){
        x=_x,y=_y;
    }
};

point pts[N];

point operator-(point a, point b){
    return point(a.x-b.x,a.y-b.y);
}

point operator+(point a, point b){
    return point(a.x+b.x,a.y+b.y);
}

const double eps = 1e-8;

set<PII> isExist;

int vis[N];

LL dot(point a, point b){
    return 1ll*a.x*b.x+1ll*a.y*b.y;
}

double L(point a){
    return sqrt(1.0*a.x*a.x+1.0*a.y*a.y);
}

bool check(point v){
    memset(vis,0,sizeof vis);
    for(int i=1;i<=n;++i){
        if(vis[i])continue;
        for(int j=1;j<=n;++j){
            if(vis[j])continue;
            point m=pts[i]+pts[j];
            point d=pts[i]-pts[j];
            if(dot(d,v)!=0)continue;
            else if(abs(abs(dot(m,v))-L(m)*L(v))>eps)continue;
            else{
                vis[i]=vis[j]=1;
            }
        }
    }

    bool ok=1;
    for(int i=1;i<=n;++i)if(!vis[i])ok=0;
    return ok;
}

int main(){
    n=read();
    for(int i=1;i<=n;++i){
        int xx=read(),yy=read();
        pts[i]=point(xx,yy);
    }

    int res=0;
    for(int i=1;i<=n;++i){
        int xx=pts[i].x,yy=pts[i].y;
        if(xx&&yy){
            int g=__gcd(xx,yy);
            xx/=g;yy/=g;
        }else{
            if(!xx)yy=1;
            else xx=1;
        }
        if(isExist.count(MP(xx,yy)))continue;
        if(check(point(xx,yy)))++res;
        isExist.insert(MP(xx,yy));
    }

    for(int i=1;i<=n;++i){
        for(int j=i+1;j<=n;++j){
            point m=pts[i]+pts[j];//中点都被放大两倍
            point v=pts[i]-pts[j];
            if(dot(m,v)!=0)continue;
            else{
                int& xx=m.x,&yy=m.y;
                if(!xx&&!yy)xx=v.y,yy=-v.x;

                if(xx&&yy){
                    int g=__gcd(xx,yy);
                    xx/=g;yy/=g;
                }else{
                    if(!xx)yy=1;
                    else xx=1;
                }

                if(isExist.count(MP(xx,yy)))continue;
                if(check(m)){
                    ++res;
                    isExist.insert(MP(xx,yy));
                }
            }
        }
    }

    cout<<res;
    return 0;
}

D. 小小的百鬼夜行

​ 题意:把一个字符串复制k次,然后看其中出现最多的字母出现次数。

​ 题解:先数一下每一个字符出现次数,然后乘以k,要注意会爆int,开long long。

#include<bits/stdc++.h>

using namespace std;

inline int read(){
    int res=0, f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
    return res*f;
}

const int MAXN = 200005;

int buk[26];
char s[MAXN];
int n, k;

int main(){
    n=read(),k=read();
    scanf("%s",s+1);

    for(int i=1;i<=n;++i)++buk[s[i]-'a'];
    int mx=*max_element(buk,buk+26);
    cout<<1ll*mx*k;
    return 0;
}

E. 贪玩的二小姐

​ 题意:每次翻转长度为m的区间,并且翻转的区间左端点一直往后,每次翻转输出和。

​ 题解:可以双端队列,但是蒟蒻只会抄板子。splay维护区间,不会的可以去luogu刷一刷模板题

#include<bits/stdc++.h>

using namespace std;

const int N = 1000005;
const int inf = 1e8;

#define ls(x) (bst[x].ch[0])
#define rs(x) (bst[x].ch[1])
#define getKey(x) (bst[x].key)
#define getSize(x) (bst[x].sz)
#define getFather(x) (bst[x].f)

typedef long long LL;

struct splayNode{
    int ch[2];
    int f;
    int sz;
    int key;
    int rev;
    LL sum;
    void clear(){ch[0]=ch[1]=f=rev=0;}
}bst[N];

inline bool getDir(int x){return rs(getFather(x))==x;}

int rt, cntNode, top, a[N], id[N], rub[N], n, m, q;

inline 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 getId(){//防止节点过多,我们需要设置一个垃圾堆,有废弃的节点应该优先使用
    if(top==0)return ++cntNode;
    return rub[top--];
}

void changeRev(int nd){
    swap(ls(nd),rs(nd));
    bst[nd].rev^=1;
}

void pushup(int nd){
    splayNode& x=bst[bst[nd].ch[0]], &y=bst[bst[nd].ch[1]];
    splayNode& res=bst[nd];
    int val=bst[nd].key;

    res.sum=x.sum+y.sum+val;
    res.sz=x.sz+y.sz+1;
}

void pushdown(int nd){
    if(bst[nd].rev){
        changeRev(ls(nd));
        changeRev(rs(nd));
        bst[nd].rev=0;
    }
}

void rot(int nd){
    int fa=getFather(nd),gf=getFather(fa);
    int ws=getDir(nd),ws1=getDir(fa);

    int nd1=bst[nd].ch[ws^1];

    bst[fa].ch[ws]=nd1;bst[nd1].f=fa;
    bst[gf].ch[ws1]=nd;bst[nd].f=gf;
    bst[nd].ch[ws^1]=fa;bst[fa].f=nd;
    pushup(fa);pushup(nd);
}

void splay(int nd, int goal=0){
    while(getFather(nd)!=goal){
        int fa=getFather(nd);
        int gf=getFather(fa);
        if(gf!=goal){
            if(getDir(nd)==getDir(fa))rot(fa);
            else rot(nd);
        }

        rot(nd);
    }
    if(!goal)rt=nd;
}

int kth(int k){
    int nd=rt;
    while(1){
        pushdown(nd);
        if(getSize(ls(nd))>=k)nd=ls(nd);
        else if(k==getSize(ls(nd))+1)return nd;
        else{
            k-=getSize(ls(nd))+1;
            nd=rs(nd);
        }
    }
}

int split(int s, int len){//拆出响应的区间
    int x=kth(s),y=kth(s+len+1);
    splay(x,0);splay(y,x);

    return ls(y);
}

void newNode(int nd, int x){//newc出一新节点
    bst[nd].sum=x;
    bst[nd].rev=0;
    bst[nd].sz=1;
}

void build(int s, int e, int fa){
    int mid=(s+e)>>1;int curNode=id[mid],pre=id[fa];
    if(s==e){
        newNode(curNode,a[s]);
    }

    if(s<mid)build(s,mid-1,mid);
    if(mid<e)build(mid+1,e,mid);
    bst[curNode].key=a[mid];bst[curNode].f=pre;
    pushup(curNode);
    bst[pre].ch[mid>=fa]=curNode;
}

void reverseTree(int x, int len){
    int nd=split(x,len),y=getFather(nd);
    changeRev(nd);
    pushup(y);pushup(getFather(y));
}

LL query(int x, int len){//求和
    int nd=split(x,len);
    return bst[nd].sum;
}

int main(){
    n=read(),m=read();
    a[1]=a[n+2]=-inf;

    for(int i=2;i<=n+1;++i)a[i]=read();
    for(int i=1;i<=n+2;++i)id[i]=i;
    build(1,n+2,0);

    rt=(n+3)>>1;cntNode=n+2;

    q = read();
    while(q--){
        int s = read();
        cout<<query(s,m);
        cout<<" 
"[q==0];
        reverseTree(s,m);
    }

    return 0;
}


F. 帕秋莉,go!

​ 题意:给一些字符串,构造字典序最大的回文串。

​ 题解:显然,奇数个的只能有一个,选最大的放中间,其他的偶数个按照从大到小从两端开始放就能通过。

#include<bits/stdc++.h>

#define all(x) x.begin(),x.end()
#define fi first
#define sd second
#define lson (nd<<1)
#define rson (nd+nd+1)
#define PB push_back
#define mid (l+r>>1)
#define MP make_pair
#define SZ(x) (int)x.size()

using namespace std;

typedef long long LL;

typedef vector<int> VI;

inline int read(){
    int res=0, f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
    return res*f;
}

const int N = 200005;

int buk[26], n;

char str[N];

int main(){
    n=read();
    scanf("%s", str+1);
    for(int i=1;i<=n;++i)++buk[str[i]-'a'];

    VI s, e;

    for(int i=25;i>=0;--i){
        for(int id=1;id<=buk[i]/2;++id){
            s.PB(i);
            e.PB(i);
        }
        buk[i]= buk[i]&1;
    }

    reverse(all(e));
    string res;
    for(int i=0;i<SZ(s);++i)res+=s[i]+'a';
    for(int i=25;i>=0;--i){
        if(buk[i]){
            res+=i+'a';
            break;
        }
    }
    for(int i=0;i<SZ(e);++i)res+=e[i]+'a';

    cout<<SZ(res)<<endl;
    cout<<res;


    return 0;
}

G. 三月精和子序列

​ 题意:取三个不同角标,(i,j,k),满足(i<j<k),且(s[i],s[j],s[k])互不相等。

​ 题解:对每一个字母分别考虑,枚举字母,然后把字母出现次数乘起来就可以了,注意取模。

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

typedef vector<int> VI;

typedef pair<int,int> PII;

inline int read(){
    int res=0, f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
    return res*f;
}

const int N = 1000005;

const int MOD = 1000000007;

int buk[26];
int n;
char s[N];

int main(){
    n=read();
    scanf("%s",s+1);

    for(int i=1;i<=n;++i)++buk[s[i]-'a'];

    int ans=0;

    for(int i=0;i<26;++i){
        for(int j=i+1;j<26;++j){
            for(int k=j+1;k<26;++k){
                ans+=(1ll*buk[i]*buk[j]*buk[k])%MOD;
                ans%=MOD;
            }
        }
    }
    cout<<ans;

    return 0;
}


H. 小町的烦恼

​ 题意:初始值x,每一天这个值都变成前一天的平方倍。

​ 题解:答案是(x^{2^{n}})。考虑快速幂和欧拉降幂。分母的模数应该取(MOD-1)

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

inline LL read(){
    LL res=0, f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();}
    return res*f;
}

LL x, n;

LL powmod(LL x, LL y, LL MOD){
    LL res=1;
    while(y){
        if(y&1)
            res=res*x%MOD;
        x=x*x%MOD;
        y>>=1;
    }

    return res;
}

int main(){
    x=read(),n=read();
    int MOD = 1e9+7;
    cout<<powmod(x%MOD,powmod(2,n-1,MOD-1),MOD);

    return 0;
}

原文地址:https://www.cnblogs.com/JohnRan/p/13054012.html