CSP 模拟24

A:最大或

发现如果选大的肯定不会更劣

所以直接把r选了

然后从高到低考虑r二进制下为0的位

如果l在当前位置能放 那么一定放 因为二进制由高位决定

最后直接用r或上这个值就可以了





B:答题

其实就是求 所有的(2^n)种组合中的第k大
直接折半搜索就可以了




C:联合权值·改

正解可以做到在(m^{1.5})复杂度下求三元环 很好的思路

首先把所有点按照入度排序

这样所有点可以划分为入度大于(sqrt{m})和入度小于(sqrt{m})两类

然后将所有点按照度数排序 度数相同的也要排名严格不同

然后从新编号小的点向新编号大的点连边

因为三元环表示方式一共有六种 而这样相当于人为强制规定了一种表示方法

这样对于入度小于(sqrt{m})的点 所有的点入度和不会超过m 能延伸的点也不超过(sqrt{m})

单个点的复杂度不会超过(msqrt{m})

而对于入度大于(sqrt{m})的点 所有的出边小于(m)个 所以总数也不会超过(msqrt{m})

这样就可以在(m^{1.5})复杂度内求出所有三元环

然后就容易处理了 首先处理求和

可以先把一个点周围所有点的点权加起来 然后平方

发现会有算重:

  1. 自己和自己
  2. 三元环

自己和自己的算的时候直接减掉就可以了

三元环直接在求三元环的时候判掉就可以了

对于最大值

将每个点可以i连到的点按权值排序

然后每次找到第一个合法的就可以break了

而不合法的只会是三元环 三元环不会超过(msqrt{m})

所以复杂度合法




D:你相信引力吗

单调栈

发现要求的也就是凹包

然后环的处理可以把起点直接设置为最大值

这样处理很秒因为可以少考虑很多细节

然后就是一个单调不增的单调栈

其实单调递减也可以 但是需要考虑的细节比较多

然后发现最后少算了一部分贡献就是仍然在栈中的可以绕优弧与最大值造成贡献

最后统计上就可以了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e7 + 10;
int a[maxn<<1],sta[maxn],flag[maxn];
int cnt[maxn],top,Max,pos,num;
ll ans;

int main(){
    int n; scanf("%d",&n);
    for(int i = 1;i <= n;++i) scanf("%d",&a[i]),a[i+n] = a[i],Max < a[i] ? (Max = a[i],pos = i) : a[i];
    for(int i = pos;i <= pos + n - 1;++i) {
        int sum = 0;
        while(top && a[sta[top]] < a[i]) sum += cnt[sta[top]],top--;
        sta[++top] = i; cnt[sta[top]] = 1;
        if(a[sta[top-1]] == a[sta[top]]) sum += cnt[sta[top-1]],cnt[sta[top-1]]++,top--;
        if(top == 1) ans += sum;
        else ans += sum + 1;
        if(top > 2) flag[sta[top]] = 1;
        else if(top == 2 && cnt[sta[top-1]] >= 2) flag[sta[top]] = 1;
    }
    while(top) ans += flag[sta[top]] * cnt[sta[top]],top--;
    cout << ans << endl;
    return 0;
}
如初见 与初见
原文地址:https://www.cnblogs.com/HISKrrr/p/13893491.html