首页 > 其他分享 >CSP 模拟 6

CSP 模拟 6

时间:2023-07-27 20:11:53浏览次数:38  
标签:min int max mid CSP mx 模拟 define

T1 排序

基本是原题 CF1375E

好像是简单题,考虑这个排列 \(\pi\) 的逆排列 \(\pi^{-1}\)(如果排列是 \(a_i\),则逆排列为 \(b_{a_i}=i\)),因为逆序对的定义是序列编号和数值大小关系不一样,所以在逆排列中逆序对和原排列相同,对逆排列做冒泡排序,因为冒泡排序交换的是相邻值的位置,对其他值没有影响,所以对逆排列冒泡排序的所有逆序对即为答案

点击查看代码
#include<bits/stdc++.h>
#define N 1005
#define pii pair<int,int>
#define mp make_pair
using namespace std;

int n,a[N],b[N],tot,pos[N];
pii ans[N*N];
// 爆零就爆零,天天好心情
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%d",a+i),b[a[i]]=i;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n-i;j++)
            if(b[j]>b[j+1]){
                swap(b[j],b[j+1]);
                ans[++tot]=mp(b[j],b[j+1]);
            }
    cout<<tot<<endl;
    for(int i=1;i<=tot;i++)
        printf("%lld %lld\n",ans[i].first,ans[i].second);
}

T2 Xorum

原题 CF1427E

很有意思的构造题

对于这个奇数 \(x\) 而言,我们不断把它的最高位消去即可得到 1,所以考虑如何得到这个最高位

构造方案(建议模拟一遍):

  1. 将 \(x\) 最高位和最低位对齐,设这个数为 \(y\)
  2. \(x\oplus y\) 得到一个数为 \(z\),则这个数中只有最高位被消掉
  3. \(z+y\) 构造出来一个 \(sum\),则最高位被补上,\(y\) 除最低位均左移一位
  4. 将 \(sum\oplus x \oplus y*2\) 则只剩下最高位加一位
  5. 用最高位加一位消掉 \(y\) 其他的得到最高位
点击查看代码
#include<bits/stdc++.h>
#define N 1000005
#define int long long
using namespace std;

int x,a[N],vis[64],tot;
struct node{int typ,a,b;}ans[N];
unordered_map<int,bool> exi;
// 2500 2500 2800 3200
signed main(){
    cin>>x;
    assert(x!=262143);
    while(true){
        if(x==1) break;
        int highbit=0;
        for(int i=20;i>=0;i--)
            if(x&(1ll<<i)){
                highbit=i;
                break;
            }
        int y=x;
        for(int i=0;i<highbit;i++){
            ans[++tot]=(node){1,y,y};
            y<<=1;
        }
        if(!vis[highbit+1]){
            ans[++tot]=(node){2,y,x};
            int tmp=y^x;
            ans[++tot]=(node){1,tmp,y};
            int temp=tmp+y;
            ans[++tot]=(node){2,temp,x};
            temp^=x;
            ans[++tot]=(node){1,y,y};
            ans[++tot]=(node){2,y*2,temp};
            vis[highbit+1]=1;
        }
        for(int i=highbit+1;(1ll<<i)<=y;i++){
            if(!vis[i]){
                ans[++tot]=(node){1,(1ll<<(i-1)),(1ll<<(i-1))};
                vis[i]=true;
            }
            if(y&(1ll<<i)){
                ans[++tot]=(node){2,y,(1ll<<i)};
                y^=(1ll<<i);
            }
        }
        vis[highbit]=true;
        ans[++tot]=(node){2,x,(1ll<<highbit)};
        x^=(1ll<<highbit);
    }
    cout<<tot<<endl;
    for(int i=1;i<=tot;i++)
        printf("%lld %lld %lld\n",ans[i].typ,ans[i].a,ans[i].b);
}

T3 有趣的区间问题

原题 CF1609F

序列分治,将序列分成两个部分 \([l,mid],(mid,r]\),然后只考虑跨越中点的区间答案,递归下去

定义 \(max(l,r)=\max_{i=l}^ra_i\),\(min(l,r)=\min_{i=l}^ra_i\)

双指针,设当前走到的左端点为 \(L\),定义 \(p1\) 为满足 \(max(mid+1,R)\not=max(L,R)\and min(mid+1,R)\not=min(L,R)\) 的 \(R\) 的最大值,\(p2\) 为满足 \(max(mid+1,R)\not=max(L,R)\or min(mid+1,R)\not=min(L,R)\) 的 \(R\) 的最大值,对于以当前区间为左端点 \(L\) 的情况分类讨论:

  • \(R\in (mid,p1]\) ,\(\max\) 和 \(\min\) 只和左区间相关,如果左区间 \(\max\) 和 \(\min\) \(popcount\) 相等则统计区间长度
  • \(R\in (p1,p2]\),对于左侧的 \(\max\) 和 \(\min\) 开桶维护即可
  • \(R\in (p2,r]\) 直接维护右区间对于 \(popcount\) 相等的后缀和即可
点击查看代码
#include<bits/stdc++.h>
#define N 1000005
#define int long long
#define bitcnt __builtin_popcountll
using namespace std;

int n,a[N],cnt[N],ans,mx[N],mn[N];
int buk1[64],buk2[64];
void solve(int l,int r){
    if(l==r){ans++;return;}
    int mid=(l+r)>>1;
    memset(buk1,0,sizeof(buk1));
    memset(buk2,0,sizeof(buk2));
    mx[mid]=mn[mid]=mid;mx[mid+1]=mn[mid+1]=mid+1;
    for(int i=mid+2;i<=r;i++) 
        mx[i]=a[i]>a[mx[i-1]]?i:mx[i-1],
        mn[i]=a[i]<a[mn[i-1]]?i:mn[i-1];
    for(int i=mid-1;i>=l;i--) 
        mx[i]=a[i]>a[mx[i+1]]?i:mx[i+1],
        mn[i]=a[i]<a[mn[i+1]]?i:mn[i+1];
    int p1=mid+1,p2=mid+1;
    for(int i=mid;i>=l;i--){
        while(p1<=r&&a[mx[i]]>=a[mx[p1]])
            buk1[bitcnt(a[mn[p1++]])]++;
        while(p2<=r&&a[mn[i]]<a[mn[p2]])
            buk2[bitcnt(a[mn[p2++]])]++;
        if(cnt[mx[i]]==cnt[mn[i]]) ans+=min(p1,p2)-mid-1;
        if(p2<p1) ans+=buk1[cnt[mx[i]]]-buk2[cnt[mx[i]]]; 
    }
    p1=p2=mid;
    memset(buk1,0,sizeof(buk1));
    memset(buk2,0,sizeof(buk2));
    for(int i=mid+1;i<=r;i++){
        while(p1>=l&&a[mx[i]]>a[mx[p1]])
            buk1[bitcnt(a[mn[p1--]])]++;
        while(p2>=l&&a[mn[i]]<=a[mn[p2]])
            buk2[bitcnt(a[mn[p2--]])]++;
        if(cnt[mx[i]]==cnt[mn[i]]) ans+=mid-max(p1,p2);
        if(p1<p2) ans+=buk1[cnt[mx[i]]]-buk2[cnt[mx[i]]]; 
    }
    solve(l,mid);solve(mid+1,r);
}

signed main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        scanf("%lld",a+i),
        cnt[i]=bitcnt(a[i]);
    solve(1,n);
    cout<<ans;
}

T4 无聊的卡牌问题

原题 CF1427F

考虑贪心,塞进一个栈里,如果顶端有三个相同先后手的点,则弹出,将三个点压成一个点连上栈顶节点,表示比它后取,然后拓扑排序即可,但是需要注意的是,必须留一个后手的根,避免出现错误,正确性证明考虑每次拿一个先手或后手产生的影响

点击查看代码
#include<bits/stdc++.h>
#define N 1205
using namespace std;

int n,visf[N],stk[N],top,id[N],tot,Cnt[N];
int fuck[N][4],fa[N],typ[N],deg[N],vis[N];
inline int read(){
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*f;
}

int main(){
    cin>>n;
    for(int i=1;i<=n*3;i++){int x=read();visf[x]=1;}
    for(int i=1;i<=n*6;i++){
        if(!top||typ[stk[top]]!=visf[i]){
            typ[++tot]=visf[i];
            stk[++top]=tot;
            fuck[tot][++Cnt[tot]]=i;
        }
        else{
            fuck[stk[top]][++Cnt[stk[top]]]=i;
            if(Cnt[stk[top]]==3) fa[stk[top]]=stk[top-1],top--;
        }
    }
    // for(int i=1;i<=tot;i++)
    //     printf("%d %d %d %d %d\n",fa[i],typ[i],fuck[i][1],fuck[i][2],fuck[i][3]);
    int cnt=0;
    for(int i=1;i<=tot;i++){
        if(!fa[i]&&!typ[i]) cnt++;
        deg[fa[i]]++;
    }
    int now=1;
    // cout<<tot<<endl;
    for(int i=1;i<=tot;i++){
        for(int j=1;j<=tot;j++)
            if(!deg[j]&&typ[j]==now&&!vis[j]){
                if(cnt==1&&i<tot&&(!fa[j])&&(!typ[j])) continue;
                vis[j]=1;deg[fa[j]]--;
                if(!typ[j]&&!fa[j]) cnt--;
                printf("%d %d %d\n",fuck[j][1],fuck[j][2],fuck[j][3]);
                break;
            }
        now^=1;
    }
}

标签:min,int,max,mid,CSP,mx,模拟,define
From: https://www.cnblogs.com/Rolling-star/p/17585817.html

相关文章

  • CSP模拟7
    A.卷一道可爱的树形DP喵!题目保证了\(w_i\)是在给定范围内随机生成的,所以不会炸精度。首先明确题意,是求出最大乘积独立集之后取模,而不是边乘边取模。边乘边取模会炸,例如\(10^9+8\)对\(10^9+7\)取模后小于\(2\),但显然\(10^9+8>2\)。那怎么办呢?高精?可以用我们......
  • CSP 模拟 5
    T1第一题贪心,观察肯定是从较浅的点上来一个士兵或者从根节点来一个士兵,用set或者vector启发式合并维护这个过程即可点击查看代码#include<bits/stdc++.h>#defineN100005#defineinf0x3f3f3f3f#definepiipair<int,int>#definempmake_pairusingnamespacestd;......
  • set.a.light 3D STUDIO - 3D摄影棚模拟布光软件mac/win版
    set.a.light3DSTUDIO是一款专业的摄影灯光模拟软件,为摄影师和摄影爱好者提供了一个真实、细致的虚拟摄影棚环境。它可以帮助用户在计算机上进行灯光设置和调整,以达到理想的照片效果。→→↓↓载set.a.light3DSTUDIO set.a.light3DSTUDIO具有丰富的功能和直观的界面,使用......
  • 第一次模拟赛总结
    第一次摸底考试总结考试结果成绩:\(100+100+80+0+70+0=350\)排名:#\(18\)逐题分析C钱到题出现の问题约瑟夫环使用了数组进行维护,取模麻烦,使用std::queue更为方便坑点队列q需要进行初始化正确代码#include<bits/stdc++.h>usingnamespacestd;intmain(){......
  • 2023 暑假集训模拟赛 Day 3
    比赛题目共\(2\)套,其中初赛题\(1\)套,复赛\(2\)题。比赛时间:\(10:50-12:00a.m\)。Part0x01过程-Process\(8:30\,a.m.\)做初赛题目;\(10:40\,a.m.\)拿到题目;\(10:41\,a.m.\)先写\(\text{T1}\),发现有点像分类讨论;\(10:50\,a.m.\)发现\(\text{T1}\)不需要那......
  • CSP6
    T1题目描述给出一个长为的排列,请你把它排序。排序方法是:定义一种操作表示交换,先找到所有逆序对满足,任意排成一个排列,使得按照这个顺序操作以后是单调递增的。如果有多种排列,输出任意一种。输入格式第一行输入,第二行输入数组。保证是排列。输出格式如果不存在答案,输出。否则......
  • 【垫底模拟】CSP模拟-6
    新系列,系列名叫垫底模拟,厉害吧T1排序最开始想的都是很简单的东西,就是把最大的数放到最后嘛,然后发现显然不行,比如说:hack:input:515324output:34252423题目很明显地告诉我们先输出逆序对数\(m\)再输出交换\(m\)行操作,这\(m\)次操作还必须针对我们求......
  • 视频直播系统源码,vue自定义模拟滚动条
    视频直播系统源码,vue自定义模拟滚动条vscroll自定义滚动条模板 <template> <divclass="vui__scrollbar"ref="ref__box"@mouseenter="handleMouseEnter"@mouseleave="handleMouseLeave"v-resize="handleResize">  <div:......
  • 2023 暑假集训模拟赛 Day 2
    比赛题目共2套,其中初赛题1套,复赛2题。比赛时间:\(10:50-12:00a.m\)Part0x01过程-Process\(8:40\,a.m.\)做初赛题目;\(10:40\,a.m.\)拿到题目;\(10:51\,a.m.\)先写\(\text{T2}\),发现是初赛考过的题目,但时限变小;\(11:20\,a.m.\)在\(\text{T2}\)上花了太久,没调出来,......
  • 蒙特卡洛模拟
    MonteCarloSimulationIntroduction蒙特卡洛是西欧小国摩纳哥最著名的一区,以豪华的赌场闻名于世。(赌场,意味着大量重复的随机过程)蒙特卡洛模拟是一种,通过大量随机采样,预测不确定事件可能结果的的数学技术。这个想法的数学保证是大数定律(Lawoflargenumbers):样本数量越多,则其算......