Comet OJ - Contest #13 补题题解

A.险恶的迷宫

题意:在二维平面坐标内,给出一个圆心坐标 (a,b),以及圆的半径 r , 再给出 n 个点的坐标 (x_i,y_i),  求有多少点在圆内。

数据范围:0  <  n  <= 1e5,      0< r , x , y  <=1e9

思路:对于判断距离根据勾股定理: sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) <= r ,即在圆的范围内。由于此题数据较大,sqrt可能导致精度损失,所以直接开long long 进行平方比较 :(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2 )<= r*r;

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxn = 1e5+7;

int main(){
    int n;
    ll a,b,r;
    cin>>n>>a>>b>>r;
    int ans = 0;
    for(int i=1;i<=n;i++){
        ll x,y;
        cin>>x>>y;
        if((x-a)*(x-a)+(y-b)*(y-b)<=r*r) ans++;
    }
    cout<<ans<<endl;
}

B.夕日的光辉

题意:给出长为 n 的字符串 str . 找到pink的子串序列.  求符合条件组成的pink自序列,相邻两个 ( 比如p与i互相相邻,n与k互相相邻 ) 最大坐标差-1
思路:贪心:求p-i间隔最大时,i-n间隔最大时,n-k坐标间隔最大时.  比如要使p-i坐标差最大,即p取其能取道的最左边,i取其符合条件组成的最右边。

code:

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxn = 1e6+7;
const int inf = 0x3f3f3f3f;
int p0[maxn];
int p1[maxn];
int p2[maxn];
int p3[maxn];

int fismin(int com,int p[],int len){
//找到第一个大于该数的位置
    for(int i=1;i<=len;i++){
        if(p[i]>com) return i;
    }
//没找到返回0
    return 0;
}
int fismax(int com,int p[],int len){
//找到最后一个小于该数的位置
    if(p[len]<com) return len;
    else{
        for(int i=1;i<=len;i++){
            if(p[i]>com) return i-1;
        }
        return len;
    }
}
int main(){
    int T;
    cin>>T;
    string s;
    while(T--){
        int len;
        cin>>len;
        cin>>s;
        int f0,f1,f2,f3;
        f0 = f1 = f2 = f3 = 0;
        //p-i间隔最大
        for(int i=0;i<len;i++){
            if(s[i]==‘p‘) p0[++f0] = i;
            if(s[i]==‘i‘) p1[++f1] = i;
            if(s[i]==‘n‘) p2[++f2] = i;
            if(s[i]==‘k‘) p3[++f3] = i;
        }
        int ans = -1;
        if(f0&&f1&&f2&&f3){
            int ff1,ff2;
            //1.p0最左边,p3最右边,p2仅此p3右,p1仅此p2右 p0-p1
            ff2 = fismax(p3[f3],p2,f2);
            if(ff2){
                ff1 = fismax(p2[ff2],p1,f1);
                if(ff1) ans = max(ans,p1[ff1]-p0[1]);
            }
            //2.po最左边,p1仅次p0左,p3最有,p2仅存p3右 p1-p2
            ff1 = fismin(p0[1],p1,f1);
            ff2 = fismax(p3[f3],p2,f2);
            if(ff1&&ff2){
                ans = max(ans,p2[ff2]-p1[ff1]);
            }
            //3.p0左,p1仅此左,p2仅此左,p3最右
            ff1 = fismin(p0[1],p1,f1);
            if(ff1){
                ff2 = fismin(p1[ff1],p2,f2);
                if(ff2) ans = max(ans,p3[f3]-p2[ff2]);
            }

            if(ans<0) cout<<-1<<endl;
            else cout<<ans-1<<endl;
        }else{
            cout<<-1<<endl;
        }
    }
}

C.序列

题意:初始长为 n 的 0 序列, 进行m次操作。每次操作给出区间 (l,r) ,将编号为奇数的序列 区间内的数字全部改成 第i次 操作的 i .同时在每一次操作前,把所有的序列复制一份。(如果还没理解题意,可以看下原题样例解析)

求每次操作后的极大连续段的个数总和。

思路:计数问题:由于是统计极大连续段(连续子区间)个数,所以我们可以 像dp计数一样,记录 以 x 位置结束(右端)的连续子区间个数 f [x]。比如初始时 长为 3的0序列,f[3] = 1;

对于每次区间更改:我们可以知道 (l-1) 与l ,(r+1)与r的值肯定不一样,所以每次修改操作后 f[l-1] 与 f [r]的贡献值会增大,而增加的个数则是倍增的个数,即第i次操作时 2^(i-1)。

对于没有修改的位置的贡献,由于每次倍增,所以统计个数时就将其乘以2.

最后统计答案,就把所有位置的贡献相加即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2019;
const ll mod=20050321;
int n,m;
ll f[maxn],p[maxn];
//定义fx表示的序列中,存在极大连续段右端点为x的序列个数
//x = n,a_x != a_x+1,
//每一次不同的统计在于从1-n此时所有的值的贡献
//由于每次对l,r操作后的值不同,又每次更新2^(i-1)个序列贡献,所以fr = fr + 2^(i-1);
//由于1~i-1与r+1~n的部分元素没有改变,所以贡献翻倍
int main()
{
    cin>>n>>m;
    //预处理2^(i-1)
    p[0]=1;for(int i=1;i<=m;i++)p[i]=(p[i-1]*2)%mod;
    f[n]=1;
    for(int i=1;i<=m;i++)
    {
        int l,r;
        cin>>l>>r;

        for(int j=1;j<l-1;j++) f[j]=(f[j]*2)%mod;
        for(int j=r+1;j<=n;j++) f[j]=(f[j]*2)%mod;

        f[l-1]=(f[l-1]+p[i-1])%mod;
        f[r]=(f[r]+p[i-1])%mod;

        ll ans=0;
        for(int j=1;j<=n;j++) ans=(ans+f[j])%mod;
        cout<<ans<<endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Tianwell/p/11827843.html

时间: 2024-07-29 12:08:34

Comet OJ - Contest #13 补题题解的相关文章

Comet OJ - Contest #13

第一次打这种比赛.还是有不少问题的,以后改吧. A题WA了两次罚了不少时. C写到一半发现只能过1,就先弃了. D一眼没看出来.第二眼看出来就是一个类似于复数的快速幂. 然后B切了. 最后切C,图中还重构了一次.还TLE了3发.浪费了大量时间. Tips: 1.A题FB基本上拿不到的,好好写1A就没事了. 2.先看一遍,大码题和数据结构放后面. 3.先开数论,就TM死刚数论.(这次要是切A之后直接刚D就有FB了) 4.别急,奖励拿不拿就那样吧. 下面是solution: A 签到题. #incl

Comet OJ - Contest #13 「佛御石之钵 -不碎的意志-」(困难版) 并查集

题意 给一个$ n \times m$ 的网格,每个格子里有一个数字,非 \(0\) 即 \(1\),行从上往下依次编号为 \(1, 2, \cdots, n\),列从左往右依次编号为 \(1, 2, \cdots, m\). 给 \(q\) 次操作,每次给定一个以 \((x_1,y_1)\) 为左上角,\((x_2,y_2)\) 为右下角的矩形内所有格子里的数字都变成 \(1\).问每次操作之后,所有数字为 \(1\)的格子构成的四连通块的个数. \(1<=n,m<=1000\) \(1&l

符文能量(Comet OJ - Contest #8)

给Comet OJ打个小广告,挺好用的,比较简洁,给人感觉很好用 Contest #8是我打的第一场本oj比赛,很遗憾A了前两道傻逼题就没思路了,然后就不打算打了....... https://www.cometoj.com/contest/58/problem/C?problem_id=2760 怎么做啊完全不会啊我那么菜,虽然看到是dp但嫌太麻烦就放弃了: 靠后仔细想了想原来这道题很简单: 结构体node e[];储存ai,bi值(当然你用数组我也不拦着),因为合并的方式很特殊,可以不管合并

Comet OJ - Contest #5

Comet OJ - Contest #5 总有一天,我会拿掉给\(dyj\)的小裙子的. A 显然 \(ans = min(cnt_1/3,cnt_4/2,cnt5)\) B 我们可以感性理解一下,最大的满足条件的\(x\)不会太大 因为当\(x\)越来越大时\(f(x)\)的增长速度比\(x\)的增长速度慢得多 其实可以证明,最大的满足的\(x\)不会超过\(100\) 因为没有任何一个三位数的各位之和大于等于\(50\) 所以我们就直接预处理\(1-99\)所有的合法的 暴力枚举即可 其实

Comet OJ - Contest #10 B

Comet OJ - Contest #10 B 沉鱼落雁 思维题 题意 : 每个数字最多重复出现三次,有n给数字,让你尽可能的使得相同数字之间的最小距离尽可能大 思路 :分三种情况套路 设 a b c 分别代表出现 一次, 两次, 三次 数字的个数 所有元素至多出现一次,答案为 n,题目规定 所有元素至多出现两次, 例如 1 1 2,可以排列成 1 2 1,所以,答案为 1 例如 1 1 2 2 3,可以排列成 1 2 3 1 2,所有 答案为 2 思考后得出,应该尽可能的把 b 个出现两次的

集训队寒假集训第二场补题题解

补题什么的待填坑... A - Generous Kefa (语法基础) 直接开桶看看有没有超过三个的,因为题目明确提出没有气球也是可以的 代码 #include <bits/stdc++.h> using namespace std; int bk[123213]; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n,k; cin>>n>>k; string a; cin>&g

Comet OJ - Contest #15题解

A 双十一特惠 (简单版) n  <=  1e19,   1e9 > 1(8) https://www.cometoj.com/contest/79/problem/A?problem_id=4198 #include<bits/stdc++.h> using namespace std; int main(){ int t; cin >> t; while(t--) { int cnt1 = 0; int n;cin >> n; int pr[] = {1

[Comet OJ - Contest #6 C][48C 2279]一道树题_树

一道树题 题目大意: 给定一棵树,边的编号为读入顺序.现在规定,区间$[L, R]$的贡献$S(L,R)$为把编号在该区间里的边都连上后,当前形成的森林中点数大于等于$2$的联通块个数. 求$\sum\limits_{i = 1} ^ {N - 1}\sum\limits_{j = i} ^ {N - 1}S(i,j)$. 数据范围:$2\le N\le 10^5$. 题解: 水题. 我们发现,一棵树上假设联通了$k$条边,那么联通块个数就是$N-k$个.所以我们可以求出,所有区间下的所有联通块

Comet OJ - Contest #8题解

传送门 \(A\) 咕咕咕 const int N=1005; char s[N][N];int len[N],n,id; inline bool cmp(R int j,R int k){ R int l=min(len[j],len[k]); fp(i,1,l)if(s[j][i]!=s[k][i])return s[j][i]<s[k][i]; return len[j]<len[k]; } int main(){ scanf("%d",&n),id=1; f