Codeforces Hello 2020——A-E題解

比賽鏈接:https://codeforces.com/contest/1284

A題 New Year and Naming

題解:

當時第一思路是求出循環節就行了,不過處理的時候需要特判是n的倍數或是m的倍數的情況。

比賽完看了zzq的代碼,真的簡介,我們從0開始讀入字符串,這樣詢問的時候直接模擬輸出就行了。

代碼實現:

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#define PI atan(1.0)*4
#define E 2.718281828
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define debug printf("ac\n");
using namespace std;
inline int read()
{
    int a=0,b=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
            b=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        a=(a<<3)+(a<<1)+c-'0';
        c=getchar();
    }
    return a*b;
}
const int INF = 0x3f3f3f3f;
string s1[27],s2[27];
string ans[100005];
int main(){
    int n=read(),m=read();
    rp(i,0,n-1) cin>>s1[i];
    rp(i,0,m-1) cin>>s2[i];
    int q=read();
    while(q--){
        int y=read();y--;
        cout<<s1[y%n]<<s2[y%m]<<endl;    
    }
    return 0;
}

B.New Year and Ascent Sequence

題解:

首先我們需要求出每一個序列的最小值和最大值,以及是否序列本身有ascent。

我們可以考慮如果一個序列的最大值大於另一個序列的最小值,那麼就是符合的。

而且如果一個序列本身有ascent的,我們可以假設他的最小值爲-1,最大值爲INF,意味着無論這個序列和誰拼接都是符合的。

然後就有兩種處理方法:前綴和或者二分。

第一種方法:我們可以維護一個最小值的前綴和pre,然後對每個序列而言,對答案的貢獻就pre[MAX[i]],表示前面有多少個序列的最小值是小於當前序列的最大值(即符合條件的)。注意這裏

第二種方法:我們可以對最大值進行排序,然後去二分大於當前最小值的最大值個數就行了。

前綴和代碼實現:

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#define PI atan(1.0)*4
#define E 2.718281828
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define debug printf("ac\n");
using namespace std;
inline int read()
{
    int a=0,b=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
            b=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        a=(a<<3)+(a<<1)+c-'0';
        c=getchar();
    }
    return a*b;
}
const int INF = 0x3f3f3f3f;
const int N = 1e6+100;
int pre[N],MIN[N],MAX[N];
int main(){
    int n=read();
    rp(i,1,n){
        MIN[i]=INF;
        int flag=0;
        int l=read();
        rp(j,1,l){
            int x=read();
            MIN[i]=min(x,MIN[i]);
            MAX[i]=max(x,MAX[i]);
            if(MIN[i]<x&&j!=1) flag=1;
        }
        if(flag) MIN[i]=-1,MAX[i]=N-1;
        pre[MIN[i]+1]++;
    }
    rp(i,1,N-1) pre[i]+=pre[i-1];
    ll ans=0;
    for(int i=1;i<=n;i++) ans+=pre[MAX[i]];
    cout<<ans<<endl;
    return 0;
}

二分的代碼實現(沒寫,copy的網上的代碼)

#include<iostream>
#include<vector>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
vector<int> MAX;
vector<int> MIN;
int main(){
    int t;
    cin>>t;
    for(int i = 0;i<t;i++){
        int Length;
        cin>>Length;
        long long Min = 999999999;
        long long Max = -1;
        int ok = 0;
        for(int j = 0;j<Length;j++){
            long long cur;
            cin>>cur;
            if(cur> Min && ok == 0){
                ok = 1;
            }
            Min = min(Min,cur);
            Max = max(Max,cur);
        }
        if(ok == 0){
            MAX.push_back(Max);
            MIN.push_back(Min);  
        }
        else{
            MAX.push_back(9999999);
            MIN.push_back(-1);  
        }
    }
    sort(MAX.begin() ,MAX.end() );
    long long ans = 0;
    for(int i = 0;i<t;i++){
        ans+=(MAX.end() -upper_bound(MAX.begin() ,MAX.end() ,MIN[i]));
        //cout<<ans<<endl;
    }
    cout<<ans;
    return 0;
}

C題 New Year and Permutation

題解:

組合排列題,首先我們考慮長度爲n的排列中,長度爲k的framed segment滿足長度爲k的子串中最大值-最小值=k.

舉個例子,長度爲5的排列中,長度爲3的framed-segment有123,234和345.然後我們考慮把這長度爲k的排列看成一個整體。那麼長度就縮小成了n-k+1,長度爲k的framed-segment的排列有(n-k+1)中,每一種的排列有k!個,最後整體的排列爲(n-k+1)!個。因此對答案的貢獻爲(n-k+1)*k!*(n-k+1)!。

因此只要我們預處理出階乘就行了。

代碼實現:

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#define PI atan(1.0)*4
#define E 2.718281828
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define debug printf("ac\n");
using namespace std;
inline int read()
{
    int a=0,b=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
            b=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        a=(a<<3)+(a<<1)+c-'0';
        c=getchar();
    }
    return a*b;
}
const int INF = 0x3f3f3f3f;
const int N = 250007;
int a[N];
int main(){
    int n=read(),m=read();
    a[0]=1;
    rp(i,1,n) a[i]=1ll*a[i-1]*i%m;
    ll sum=0;
    rp(i,1,n) sum=(sum+1ll*(n-i+1)*a[i]%m*a[n-i+1]%m)%m;
    cout<<sum<<endl;
    return 0;
}

 D題New Year and Conference

詳細題解:https://blog.csdn.net/qq_43472263/article/details/104276639

代碼實現:

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#define PI atan(1.0)*4
#define E 2.718281828
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define debug printf("ac\n");
using namespace std;
inline int read()
{
    int a=0,b=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
            b=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        a=(a<<3)+(a<<1)+c-'0';
        c=getchar();
    }
    return a*b;
}
const int INF = 0x3f3f3f3f;
const int N = 1e5+7;
struct node{
    int sa,ea,sb,eb;
    node(){};
    node(int sa,int ea,int sb,int eb):sa(sa),ea(ea),sb(sb),eb(eb){};
    bool operator<(const node& others){
        return sa==others.sa?ea<others.ea:sa<others.sa;
    }
}p[N];
int MAX[N<<2],MIN[N<<2];
void pushup(int rt){
    MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]);
    MIN[rt]=min(MIN[rt<<1],MIN[rt<<1|1]);
}
void build(int l,int r,int rt){
    if(l==r){
        MAX[rt]=p[l].sb;
        MIN[rt]=p[l].eb;
        return ;
    } 
    int m=l+r>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
int queryMIN(int l,int r,int rt,int ql,int qr){
    if(ql<=l&&r<=qr) return MIN[rt];
    int m=l+r>>1;
    if(qr<=m) return queryMIN(lson,ql,qr);
    else if(ql>=m) return queryMIN(rson,ql,qr);
    else return min(queryMIN(lson,ql,m),queryMIN(rson,m+1,qr));
}
int queryMAX(int l,int r,int rt,int ql,int qr){
    if(ql<=l&&r<=qr) return MAX[rt];
    int m=l+r>>1;
    if(qr<=m) return queryMAX(lson,ql,qr);
    else if(ql>=m) return queryMAX(rson,ql,qr);
    else return max(queryMAX(lson,ql,m),queryMAX(rson,m+1,qr));
}
bool solve(int n){
    sort(p+1,p+1+n);
    build(1,n,1);
    rp(i,1,n){
        int pos=lower_bound(p+1,p+1+n,node(p[i].ea,INF,0,0))-p-1;
        if(i+1>pos) continue;
        if(queryMIN(1,n,1,i+1,pos)<p[i].sb||queryMAX(1,n,1,i+1,pos)>p[i].eb) return false;
    }
    return true;
}
int main(){
    int n=read();
    rp(i,1,n) p[i].sa=read(),p[i].ea=read(),p[i].sb=read(),p[i].eb=read();
    int cnt=0;
    if(solve(n)) cnt++;
    rp(i,1,n) swap(p[i].sa,p[i].sb),swap(p[i].ea,p[i].eb);
    if(solve(n)) cnt++;
    if(cnt==2) cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
    return 0;
}

E題 New Year and Castle Construction

題目大意:

給n個點,問存在多少個四個點圍成的四邊形(可能是凹四邊形,這樣圍成的就是三角形)嚴格包圍某個點。

不存在三點共線,支持複雜度O(n*n*logn)。

題解:

首先我們可以求出所有情況,然後減去那些四邊形不包含某個點的情況。

這個題基於一個結論,如果我們任取兩個點構成一條邊,我們可以求出這條邊上面的所有點,這樣在這些點中任取三個點和組成邊的那個點組成的四邊形不包含組成邊的另一個點。

首先我們可以枚舉一個點,然後其他點與當前枚舉的那個點進行極角排序,之後我們再枚舉其他的所有點,按照上面那個結論求出答案,然後減去就行了。

注意精度問題,需要用long double來存儲點和角度,表示PI的時候需要用acos(-1.0L),也是精度問題。

代碼實現:

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#define E 2.718281828
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define debug printf("ac\n");
using namespace std;
inline int read()
{
    int a=0,b=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
            b=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        a=(a<<3)+(a<<1)+c-'0';
        c=getchar();
    }
    return a*b;
}
const int INF = 0x3f3f3f3f;
const int N = 2507;
long double x[N],y[N],PI=acos(-1.0L);
int main(){
    int n;
    cin>>n;
    rp(i,0,n-1) cin>>x[i]>>y[i];
    ll ans=1ll*n*(n-1)*(n-2)*(n-3)*(n-4)/24;//n個點選四個共有res種情況
    rp(i,0,n-1){
        vector<long double> v;
        rp(j,0,n-1){
            if(i==j) continue;
            v.pb(atan2(y[j]-y[i],x[j]-x[i]));//求出相對於當前點的角度(極角)
        }
        sort(v.begin(),v.end());//極角排序
        int size=n-1,index=0;
        rp(j,0,size-1){//枚舉另一個點組成邊
            while(index<j+size){//統計在邊上面的點的個數
                long double ang=v[index%size]-v[j];//求出index點相對j點的角度,需要環形的枚舉出當前邊的兩個點的所有點
                if(ang<0) ang+=2*PI;//角度小於0的話再走一圈
                if(ang<PI) index++;
                else break; //在下方的話就跳出
            }
            ll cnt=index-j-1;//枚舉到相對於j的角度大於等於180爲止,共有index-j個點,不包括j,故再-1
            ans-=1ll*cnt*(cnt-1)*(cnt-2)/6;//在這些點裏面任取三個點的構成的答案即爲不符合條件的,減去就行
        }
    }
    cout<<ans<<endl;
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章