codeforces gym 102268 300iq round

暂时只能写签到题,别的题解之后补

A.Angle Beats

B.Best Subsequence

有点有趣的二分

显然二分之后就是找到一个长度恰好为k的合法环了

先证明一个引理,如果可以找到一个长度大于k的环一定可以找到一个长度等于k的环

固定头尾不动之后就可以使用归纳法证明一个长度大于3的环都可以删掉一个点

为啥呢?,因为考虑任意三个连续的点,除非中间的点是最小值,否则都可以删掉这个点

很容易证明长度大于3的序列至少存在一组三个连续的点满足中间的点可以删去吧

而长度恰好是3的时候吧中间的点删掉就行了,因为头尾是合法的

这样的话我们的目标就是dp出最长的环了

那么dp出最长的环需要借助另一个结论优化到\(O(nlogn)\)

我们将整个序列按照这样的方式切分成若干个段

找到整个序列的最小值,然后把最小值之前的点全部分成一个段,递归切分剩下的段

这样分好段之后我们把每一段的末尾成为关键点

我们断言(证明反证),一个最长环一定可以在关键点结尾

并且当我们固定了一个环的头尾之后,最长环的必定经过头尾间的所有关键点

这样有什么用呢?

当然拿来辅助dp啊,显然最长链一个树状数组搞定

加上环的限制就是开头定死之后结尾小于一定数值了

显然扫描线可以干掉限制,依次允许一些点成为结尾,然后查询某些开头的dp值即可

我们刚才结论决定了只需要考虑所有的关键点即可,并且容易发现关键点的权值随着位置递增

这就简单多了,你会发现每个点出发的链一定会经过离自己最近的关键点,后面的转移完全一样

所以一段一段的插入dp值就行了,预处理每个点到关键点的最长链(树状数组做)

然后关键点和关键点之间的dp拿前缀和处理就行了

复杂度二分套dp\(O(nlog^2n)\)

#include
#include
using namespace std;const int N=4*1e5+10;typedef long long ll;
int n;int k;int S;
struct linetree
{   
    int ta[N];
    inline void ins(int x,int t)
    {
        for(;x<=n;x+=x&(-x))ta[x]=max(ta[x],t);
    }
    inline int qry(int x)
    {
        int r=-0x3f3f3f3f;
        for(;x;x-=x&(-x))r=max(r,ta[x]);
        return r;
    }
    inline void ih()
    {
        for(int i=0;i=lst)
        {
            for(int j=lst;j<=srt[i];j++)bel[j]=srt[i];
            lst=srt[i]+1;
        }
    rk[srt[1]]=1;
    for(int i=2;i<=n;i++)
        rk[srt[i]]=rk[srt[i-1]]+(a[srt[i]]!=a[srt[i-1]]);
}
int currk[N];
inline bool jud(int lim)
{
    //printf("jud %d\n",lim);
    ll res=-0x3f3f3f3f;
    for(int i=1;i<=n;i++)dp[i]=-0x3f3f3f3f;
    for(int i=1;i<=n;i++)dis[i]=0;
    int lst=1;int mend=0;
    lt.ih();
    for(int i=n,j=0;i>=1;i--)
    {
        while(a[srt[j+1]]+a[srt[i]]<=lim&&j!=n)j++;
        currk[srt[i]]=rk[srt[j]];
    }
    for(int i=n,j=1;i>=1;i--)
    {
        int id=srt[i];
        while(a[srt[j]]+a[id]<=lim&&j<=n)
        {
            if(srt[j]>=lst)
            {
                int val=-0x3f3f3f3f;
                lt.ins(rk[srt[j]],1);
                dp[srt[j]]=1;
                if(a[lst-1]+a[srt[j]]<=lim)val=max(val,dp[srt[j]]);
                for(int z=srt[j]-1;z>=lst;z--)
                    if(a[z]=lst;z--)lt.d(rk[z]);
                dis[srt[j]]=dis[lst-1]+val;
                lst=srt[j]+1;
                if(val>0)mend=lst-1;
            }
            j++;
        }
        res=max(res,dis[mend]-dis[bel[id]]+dp[id]);
        if(res>=k)return true;
    }
    return res>=k;
}
int sum1=0;
inline int bigr(){return (rand()<<16)+rand();}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    //  srand(233);
    //n=200000;k=n;
    //for(int i=1;i<=n;i++)
    //  scanf("%d",&a[i]);
//  for(int i=1;i<=n;i++)
    //  a[i]=bigr()%(int)(1e9);
    pre();
    for(int i=1;i<=n;i++)
        sum1=max(sum1,a[i]);
    int l=2;int r=sum1*2;
//  printf("%d\n",r);
    while(l!=r)
    {
        int mid=(((ll)l+(ll)r))>>1;
        if(jud(mid))r=mid;else l=mid+1;
    }
    printf("%d",l);
    return 0;
}

C.Cool Pairs

D.Dates

E.Expected Value

F.Free Edges

G. Graph Counting

H. Hall's Theorem

I.Interesting Graph

J.Jealous Spilt

K.Knowledge

转载于:https://www.cnblogs.com/sweetphoenix/p/11172948.html

你可能感兴趣的:(codeforces gym 102268 300iq round)