【暴力搜索】【莫队算法】【贪心】[Codeforces Round #340 (Div. 2) ]题解报告

A. Elephant

http://codeforces.com/contest/617/problem/A
完全就是贪心的裸题可以很容易的发现要走尽量多的步数才能走到最接近n的地方,然后判断是不是刚好走到n就行了

#include <cstdio>
int main(){
    int n;
    scanf("%d", &n);
    printf("%d\n", n/5+int(n%5>0));

    return 0;
}

B. Chocolate

http://codeforces.com/contest/617/problem/B
可以发现对于每一块巧克力至少有1个,那么每一次多出1个坚果那么就有之前那么多个空位可以选择,乘上(空位数量+1)就好了,在这里注意特判全部都是0的情况和记得开long long

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 100;
int s[MAXN+10];
int main(){
    int n, sum=0;
    scanf("%d", &n);
    for(int i=1;i<=n;i++)
        scanf("%d", &s[i]), sum+=s[i];
    if(!sum){
        printf("0\n");
        return 0;
    }
    int l = 1;
    while(!s[l]) l++;
    long long cnt=1, counter=1;
    for(int i=l;i<=n;i++){
        if(s[i]==0) counter++;
        else{
            cnt *= counter;
            counter = 1LL;
        }
    printf("%I64d\n", cnt);

    return 0;
}

C. Watering Flowers

http://codeforces.com/contest/617/problem/C
以第一个圆心枚举半径然后判断到第二个圆心的最远的不属于第一个圆心的点的距离,住注意特殊处理第一个圆心半径为0的情况,同时记得开个long long

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 2000;
long long s[MAXN+10][2];
long long PF(long long u){return u*u;}
int main(){
    long long n, x1, x2, y1, y2;
    scanf("%I64d%I64d%I64d%I64d%I64d", &n, &x1, &y1, &x2, &y2);
    long long ans = 0x7fffffffffffffff;
    for(long long i=1;i<=n;i++)
        scanf("%I64d%I64d", &s[i][0], &s[i][1]);
    s[0][0] = x1, s[0][1] = y1;
    for(long long i=0;i<=n;i++){
        long long tmp = PF(s[i][0]-x1)+PF(s[i][1]-y1);
        long long t2 = 0;
        for(int j=1;j<=n;j++)
            if(PF(s[j][0]-x1)+PF(s[j][1]-y1) > tmp)
                t2 = max(t2, PF(s[j][0]-x2) + PF(s[j][1]-y2));
        ans = min(ans, t2+tmp);
    }
    printf("%I64d\n", ans);

    return 0;
}

D. Polyline

http://codeforces.com/contest/617/problem/D
可以通过观察发现答案其实只有1 2 3三种情况那么首先可以发现如果任意两个点在同一条直线上并且另一个点做该直线的垂线的交点在两个点的两边的延长线上(包括端点)那么之需要1次转向,否则就需要3次,1次就只有一种情况——三个点在同一条直线上

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int check(int x1, int y1, int x2, int y2){
    return x1 == x2 || y1 == y2;
}
int main(){
    int x1, x2, x3;
    int y1, y2, y3;
    scanf("%d%d", &x1, &y1);
    scanf("%d%d", &x2, &y2);
    scanf("%d%d", &x3, &y3);
    if(check(x1, y1, x2, y2) && check(x1, y1, x3, y3) && check(x2, y2, x3, y3)) printf("1\n");
    else{
        int ans = 3;
        if(check(x1, y1, x2, y2)){
            if(x1 == x2 && (y3 >= max(y1, y2) || y3 <= min(y1, y2)))
                ans = 2;
            if(y1 == y2 && (x3 <= min(x1, x2) || x3 >= max(x1, x2)))
                ans = 2;
        }
        if(check(x1, y1, x3, y3)){
            if(x1 == x3 && (y2 >= max(y1, y3) || y2 <= min(y1, y3)))
                ans = 2;
            if(y1 == y3 && (x2 <= min(x1, x3) || x2 >= max(x1, x3)))
                ans = 2;
        }
        if(check(x2, y2, x3, y3)){
            if(x3 == x2 && (y1 >= max(y3, y2) || y1 <= min(y3, y2)))
                ans = 2;
            if(y3 == y2 && (x1 <= min(x3, x2) || x1 >= max(x3, x2)))
                ans = 2;
        }
        printf("%d\n", ans);
    }

    return 0;
}

E. XOR and Favorite Number

http://codeforces.com/contest/617/problem/E
莫队算法的题目,具体内容可以参考莫队算法的论文,首先可以知道k=sum[a]^sum[b-1]因为这里sum[a]^sum[b-1]其实就是b-a之间的xor的值了那么每一次寻找有没有匹配的sum,左端点就找对应的右边的sum值得个数。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
const int MAXS = 2000000;
const int MAXN = 100000;
int val[MAXN+10], sum[MAXN+10];
long long t2[MAXS+10], t1[MAXS+10];
struct Task{
    int l, r;
    int lid, id;
    long long ans;
}Q[MAXN+10];
bool cmp(const Task &a, const Task &b) {
    if(a.lid == b.lid)
        return a.r < b.r;
    return a.lid < b.lid;
}
bool cmp2(const Task &a, const Task &b) {
    return a.id < b.id;
}
int main(){
    int n, m, k;
    scanf("%d%d%d", &n, &m, &k);
    for(int i=1;i<=n;i++) scanf("%d", &val[i]);
    sum[1] = val[1];
    for(int i=2;i<=n;i++) sum[i] = sum[i-1] ^ val[i];
    int _bit = sqrt(n + 0.5);
    for(int i=1;i<=m;i++)
        scanf("%d%d", &Q[i].l, &Q[i].r), Q[i].lid=(Q[i].l-1)/_bit+1,Q[i].id=i;
    sort(Q+1, Q+1+m, cmp);
    int l=1, r=0;
    long long tmp=0;
    for(int i=1;i<=m;i++){
        while(l < Q[i].l){
            tmp -= t2[k^sum[l-1]];
            t1[sum[l-1]]--;
            t2[sum[l]]--;
            l++;
        }
        while(l > Q[i].l){
            l--;
            t1[sum[l-1]]++;
            t2[sum[l]]++;
            tmp += t2[k^sum[l-1]];
        }
        while(r < Q[i].r){
            r++;
            t1[sum[r-1]]++;
            t2[sum[r]]++;
            tmp += t1[k^sum[r]];
        }
        while(r > Q[i].r){
            tmp -= t1[k^sum[r]];
            t1[sum[r-1]]--;
            t2[sum[r]]--;
            r--;
        }
        Q[i].ans = tmp;
    }
    sort(Q+1, Q+1+m, cmp2);
    for(int i=1;i<=m;i++)
        printf("%I64d\n", Q[i].ans);

    return 0;
}

转载于:https://www.cnblogs.com/JeremyGJY/p/5921640.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值