1. 程式人生 > >【LGR-049】洛谷7月月賽

【LGR-049】洛谷7月月賽

while size printf class jump 二分 ++ 一個 sin

Preface

Luogu八月月賽都結束了我才來補七月月賽

這次月賽還是很狗的,在紹一的晚上恰逢刮臺風,然後直接打到一半斷網了

結果都沒有交上去GG

感覺這次難度適中,解法也比較清新自然吧,十分給個九分一分因為沒的打

好了下面開始看題。


A Divided Prime

目的:送分,坑罰時

一道比較SB的題目,尤其註意題目中一個信息:

保證對於一個數字,其在\(b_i\)中出現的次數不多於在\(a_i\)中出現的次數。

然後我們發現這個式子的本質就是一些數的乘積,我們討論一下最後的結果:

  • 由兩個及以上的數相乘得來,絕對不是質數
  • 是一個數的形式,\(O(\sqrt n)\)判斷是質數還是合數

當然你不能傻乎乎地直接把一堆數乘起來,你又不是Python

我們離散化一下,然後用類似於桶一樣的操作即可實現消去

CODE

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const LL N=100005;
LL a[N],b[N],r[N<<1],t1[N<<1],t2[N<<1],tot,n,m,t,cnt,num;
bool flag;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-‘0‘,isdigit(ch=tc()));
}
inline void clear(void)
{
    memset(t1,0,sizeof(t1));
    memset(t2,0,sizeof(t2)); 
    cnt=tot=num=0; flag=1;
}
inline LL find(LL x)
{
    LL L=1,R=cnt;
    while (L<=R)
    {
        LL mid=(L+R)/2;
        if (r[mid]==x) return mid;
        if (r[mid]>x) R=mid-1; else L=mid+1;
    }
}
inline bool is_prime(LL x)
{
    if (x==1) return 0;
    for (register int i=2;i*i<=x;++i)
    if (x%i==0) return 0; return 1;
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register LL i; read(t);
    while (t--)
    {
        clear(); read(n); read(m);
        for (i=1;i<=n;++i) read(a[i]),r[++cnt]=a[i];
        for (i=1;i<=m;++i) read(b[i]),r[++cnt]=b[i];
        sort(r+1,r+cnt+1); cnt=unique(r+1,r+cnt+1)-r-1;
        for (i=1;i<=n;++i) ++t1[find(a[i])];
        for (i=1;i<=m;++i) ++t2[find(b[i])];
        for (i=1;i<=cnt;++i)
        if (t1[i]-t2[i]==1)
        {
            if (!num) num=r[i]; else { flag=0; break; }
        } else if (t1[i]!=t2[i]) { flag=0; break; }
        if (!flag||!num) puts("NO"); else puts(is_prime(num)?"YES":"NO");
    }
    return 0;
}

B River Jumping

目的:送分,連罰時都騙不到

話說這題問什麽藍了,我覺得黃題都過了

看到題目和陳瀟然大佬討論了一波覺得直接貪心地跳,每次選擇一個最近的且大於\(S\)的跳一下即可。

具體的證明感覺真的不需要

對於一段巖石\(i\in[l,r]\),若\(w_r-w_l<S\),由於來回一次的限制,中間的石塊便無法被跳完。

因此若有解,我們只需要按上面的方法做即可。

感覺沒什麽坑點,5min碼完1A當然是賽後

CODE

#include<cstdio>
#include<cctype>
using namespace std;
const int N=100005;
int n,m,s,lst,cnt,ans[N],pre[N],dis,tot,x;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-‘0‘,isdigit(ch=tc()));
}
inline void write(int x)
{
    if (x>9) write(x/10);
    putchar(x%10+‘0‘);
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i; read(n); read(m); read(s);
    for (pre[1]=0,tot=1,i=1;i<=m;++i)
    {
        read(x); if (x-lst>=s) ans[++cnt]=i,lst=x;
        else if (x-dis<s) return puts("NO"),0; else pre[++tot]=i,dis=x;
    }
    if (n-lst>=s) ans[++cnt]=i; else return puts("NO"),0;
    for (puts("YES"),i=1;i<=cnt;++i) write(ans[i]),putchar(‘ ‘);
    for (i=tot;i>=1;--i) write(pre[i]),putchar(‘ ‘);
    return 0;
}

C True Vegetable

目的:拉分題,考驗腦洞和思維

由於數據範圍我們想到二分,但不是常規的二分時間,因為這樣我們很難直接判斷

考慮二分被減的時間點。接下來我們先把題目的菜氣減去被打掉的值。

這裏忍不住又%一發出題人,把一個細節的數據\(w_i+r_{v_i}\le w_{i+1}\)藏的這麽深

所以我們發現菜氣被打掉之後總是可以漲回來的,於是直接貪心大力加即可。

考慮當前的這個點不滿足,那麽盡量向右選擇即可。

CODE

#include<cstdio>
#include<cctype>
#include<cstring>
using namespace std;
const int N=5e5+5;
int n,m,k,s,a[N],x,w[N],num[N],v[N],t[N],ans,d[N];
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-‘0‘,isdigit(ch=tc()));
}
inline int work(int x)
{
    register int i; int tot=0,step=0;
    memcpy(t,a,sizeof(t));
    memset(d,0,sizeof(d));
    for (i=1;i<=x;++i)
    t[num[i]]-=v[i];
    for (i=1;i<=n;++i)
    {
        if (t[i]+tot<1)
        {
            int dlt=1-t[i]-tot; step+=dlt; tot+=dlt;
            if (d[i+k-1]<=n) d[i+k-1]+=dlt;
        }
        tot-=d[i];
    }
    return step>w[x]?step:w[x];
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i; read(n); read(m); read(k); read(s);
    for (i=1;i<=n;++i) read(a[i]);
    for (i=1;i<=s;++i) read(x);
    for (i=1;i<=m;++i)
    read(w[i]),read(num[i]),read(v[i]);
    int l=0,r=m,mid; w[m+1]=1e9;
    while (l<=r)
    {
        mid=l+r>>1;
        if (work(mid)<w[mid+1]) ans=mid,r=mid-1; else l=mid+1;
    }
    return printf("%d",work(ans)),0;
}

D Beautiful Pair

目的:毒瘤數據結構,打壓選手的信心

看到題目發現\(O(n^2)\)的暴力是naive的,考慮優化。

由於最近做過類似的題目,我就直接考慮當\(a_i\)為一個區間\(i\in[l,r]\)中的最大值時,對答案的貢獻

首先兩邊是可以直接用單調棧\(O(n)\)搞出來的。

借鑒一下啟發式的思想,我們每一次以\(i\)為中心把區間分成左右兩邊,並挑選數字個數少的一邊直接枚舉

同時在另一邊的記錄詢問(註意這裏的詢問相當與求小於某一個數的數的數量)這個可以樹狀數組存一下

考慮我們把所有的操作都放到最後,漸進意義下期望的時間和空間復雜度都是控制在\(O(n\ logn)\)的範圍內的(好像又大佬能證明更少)

所以最後掃一次在樹狀數組上跑並且統計即可,註意區間計算之後要及時刪除

復雜度是很迷的\(O(n\ log^2n)\),結果不吸氧也能過

CODE

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;
const int N=100005;
int n,a[N],b[N],stack[N],top,front[N],back[N],num[N],tot,bit[N];
vector <int> d[N];
long long ans;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-‘0‘,isdigit(ch=tc()));
}
inline void insert(int now,int opt)
{
    if (opt)
    {
        d[now].pb(1); d[front[now]-1].pb(-1);
        for (register int i=now+1;i<=back[now];++i)
        d[now].pb(a[now]/a[i]),d[front[now]-1].pb(-a[now]/a[i]);
    } else
    {
        d[back[now]].pb(1); d[now-1].pb(-1);
        for (register int i=front[now];i<now;++i)
        d[back[now]].pb(a[now]/a[i]),d[now-1].pb(-a[now]/a[i]);
    }
}
inline int abs(int x)
{
    return x>0?x:-x;
}
inline int lowbit(int x)
{
    return x&-x;
}
inline void add(int x)
{
    while (x<=n) ++bit[x],x+=lowbit(x);
}
inline int get(int x)
{
    int tot=0; while (x) tot+=bit[x],x-=lowbit(x); return tot;
}
inline int same_find(int x)
{
    int l=1,r=tot;
    while (l<=r)
    {
        int mid=l+r>>1; if (b[mid]==x) return mid;
        if (b[mid]<x) l=mid+1; else r=mid-1;
    }
}
inline int lower_find(int x)
{
    int l=1,r=tot,res;
    while (l<=r)
    {
        int mid=l+r>>1;
        if (b[mid]<=x) res=mid,l=mid+1; else r=mid-1;
    }
    return res;
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i,j; read(n);
    for (i=1;i<=n;++i)
    read(a[i]),b[i]=a[i];
    for (i=1;i<=n;++i)
    {
        while (top&&stack[top]<=a[i]) --top;
        front[i]=top?num[top]+1:1;
        stack[++top]=a[i]; num[top]=i;
    }
    for (top=0,i=n;i>=1;--i)
    {
        while (top&&stack[top]<a[i]) --top;
        back[i]=top?num[top]-1:n;
        stack[++top]=a[i]; num[top]=i;
    }
    for (i=1;i<=n;++i)
    if (i-front[i]<=back[i]-i) insert(i,0); else insert(i,1);
    sort(b+1,b+n+1); tot=unique(b+1,b+n+1)-b-1;
    for (i=1;i<=n;++i)
    {
        add(same_find(a[i]));
        for (j=0;j<d[i].size();++j)
        {
            int s=lower_find(abs(d[i][j]));
            ans+=d[i][j]>0?get(s):-get(s);
        }
    }
    return printf("%lld",ans),0;
}

E題凸包棄療,感覺做不動

總體還可以吧,挺喜歡這次月賽的

希望下次不要斷網了

【LGR-049】洛谷7月月賽