Comet OJ - Contest #14 補題題解

A.險惡的迷宮html

題意:在二維平面座標內,給出一個圓心座標 (a,b),以及圓的半徑 r , 再給出 n 個點的座標 (x_i,y_i),  求有多少點在圓內。c++

數據範圍:0  <  n  <= 1e5,      0< r , x , y  <=1e9ide

思路:對於判斷距離根據勾股定理: sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) <= r ,即在圓的範圍內。因爲此題數據較大,sqrt可能致使精度損失,因此直接開long long 進行平方比較 :(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2 )<= r*r;spa

#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;
}
View Code

 

B.夕日的光輝code

題意:給出長爲 n 的字符串 str . 找到pink的子串序列.  求符合條件組成的pink自序列,相鄰兩個 ( 好比p與i互相相鄰,n與k互相相鄰 ) 最大座標差-1
思路:貪心:求p-i間隔最大時,i-n間隔最大時,n-k座標間隔最大時.  好比要使p-i座標差最大,即p取其能取道的最左邊,i取其符合條件組成的最右邊。htm

code:blog

#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;
        }
    }
}
View Code

 

C.序列ci

題意:初始長爲 n 的 0 序列, 進行m次操做。每次操做給出區間 (l,r) ,將編號爲奇數的序列 區間內的數字所有改爲 第i次 操做的 i .同時在每一次操做前,把全部的序列複製一份。(若是還沒理解題意,能夠看下原題樣例解析)字符串

求每次操做後的極大連續段的個數總和。get

思路:計數問題:因爲是統計極大連續段(連續子區間)個數,因此咱們能夠 像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;
}
View Code
相關文章
相關標籤/搜索