AHOI2017初中组解题报告

T1

【题目描述】
一个n*n的网格图上有m个探测器,每个探测器有个探测半径r,问这n*n个点中有多少个点能被探测到。
【输入格式】
第一行3个整数n,m,r
接下来m行,每行两个整数x,y表示第i个探测器的坐标
【输出格式】
能被探测到的点的个数
【样例输入】
5 2 1
3 3
4 2
【样例输出】
8
【数据范围】
1<=n,m<=100
【分析】
三重循环暴力判断即可。

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int sqr(int x){return x*x;}
int main(){
    int n,m,r;
    int x[105],y[105];
    scanf("%d%d%d",&n,&m,&r);
    for (int i=1;i<=m;i++) scanf("%d%d",&x[i],&y[i]);
    int ans=0;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++){
            for (int k=1;k<=m;k++){
                double dis=sqrt(sqr(x[k]-i)+sqr(y[k]-j));
                if (dis<=double(r)) {ans++;break;}
            }
        }
    printf("%d\n",ans);
}

T2

【题目描述】
有N盏灯排成一列,其中有些灯开着,有些灯关着。小可可希望灯是错落有致的,他定义一列灯的状态的不优美度为这些灯中最长的连续的开着或关着的灯的个数。小可可最多可以按开关k次,每次操作可以使该盏灯的状态取反:原来开着的就关着,反之开着。现在给出这些灯的状态,求操作后最小的不优美度。
【输入格式】
第一行两个整数n,k
第二行是一个长度为n的字符串,其中有两种字符:N和F。其中N表示该灯开着,F表示该灯关着
【输出格式】
最小的不优美度
【样例输入】
8 1
NNNFFNNN
【样例输出】
3
【数据范围】
1<=k<=n<=100000
【分析】
看上去很像DP问题?非也非也,此题其实是分治。
不优美度的定义中提到了“最长”即最大,然后题目要求最小的不优美度。最大值最小,这是经典的分治问题。
设fct(x)表示使不优美度为x时至少按多少次按钮,则可以根据fct(mid)与k的大小关系来做。注意特判最小不优美度为1的情况。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=100000+5;
char a[maxn];
int n,m;
bool check(int f){
    int ans=0;
    for (int i=2;i<=n;i++){
        if (a[i]==a[i-1] && !f){
            ans++;
            f=1;
        }
        else if (a[i]!=a[i-1] && f){
            ans++;
            f=1;
        }
        else f=0;
    }
    return ans<=m;
}
int fct(int x){
    int t=0,y=0,z=1;
    for (int i=1;a[i];i++){
        if (a[i]==a[z]) t++; else t=1,z=i;
        if (t>x){
            t=0;
            z=i+1;
            y++;
        }
    }
    return y;
}
int main(){
    scanf("%d%d%s",&n,&m,a+1);
    if (......) { printf("1\n");return 0; }//括号中的内容自己试着填一下
    int l=2,r=n;
    while (l<r){
        int mid=(l+r)/2;
        if (fct(mid)>m) l=mid+1; else r=mid;
    }
    printf("%d\n",l);
}

T3

【题目描述】
给出一个由(,),|,a组成的序列,求化简后有多少个a。
化简规则:
1、形如aa…a|aa…a|aa…a的,化简结果为“|”两边a的个数最多的一项,例如a|aa|aaa=aaa
2、先算带括号的序列,例如(a|a)|aaa=aaa
【输入格式】
一个序列
【输出格式】
最多有多少个a
【样例输入】
aa(aa)|(aa|(a|aa))aa
【样例输出】
4
【数据范围】
序列长度不超过100000
保证序列合法且括号内和“|”左右均非空
【分析】
此题看上去很烦,实际上还是不难的。
大体思路就是边读边做,读到a就把计数器加1,读到左括号就入栈(其实这里根本不需要开栈,说栈是为了方便理解),读到|就打擂台,读到右括号就返回答案。

#include<cstdio>
#include<iostream>
using namespace std;
char ch;
int dfs(){
    int i=0,ans=0;
    while(1){
        ch=getchar();
        if (ch=='a') i++;
        else if (ch=='(') i+=dfs();
        else if (ch=='|') {
            ans=max(ans,i);
            i=0;
        }
        else {
            ans=max(ans,i);
            return ans;
        }
    }
}
int main(){
    printf("%d\n",dfs());
}

总共只有0.3K的代码。。。
当时在考场写了4K多(注释大概2K)。。。

T4

【题目描述】
待更新。

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值