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

CSP模拟6

时间:2023-10-15 09:01:09浏览次数:35  
标签:cnt top id2 long da && CSP 模拟

第一场就保龄了,开门红

A. 排序

题目给出的是一个排列,所以一定会通过有限次操作来使操作有序。 (话说这题上来就搞诈骗

由于数据范围很小,我们直接 \(O(n^2)\) 暴力枚举即可。

而你需要操作逆序对个数次,所以每次交换需要让逆序对的个数减一,所以只需要每次交换值相邻的两个就可以了。

code
#include<bits/stdc++.h>
using namespace std;
const int M=1010;
int n,ans;
int a[M];
struct abc{
	int x,y;
}da[M*M];
bool cmp(abc x,abc y){
	if(x.x==y.x){
		return a[x.y]>a[y.y];
	}
	return x.x<y.x;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		for(int j=1;j<i;j++){
			if(a[j]>a[i]){
				ans++;
				da[ans].x=j;
				da[ans].y=i;
			}
		}
	}
	printf("%d\n",ans);
	sort(da+1,da+ans+1,cmp);
	for(int i=1;i<=ans;i++){
		printf("%d %d\n",da[i].x,da[i].y);
	}
	return 0;
}

B. Xorum

神奇的推式子

你已知一个奇数,需要通过两种操作来得到1。也就是说,要不断地消去该奇数每一位上的1。

设你现在的一个奇数为 \(x\)。

将 \(x\) 的最后一位挪至与第一位对齐得到 \(y\)。

\(x\) 异或 \(y\) 得到 \(z\)。

\(z\) 加上 \(y\) 得到 \(n\)。

\(y\) 加上 \(y\) 得到 \(p\)。

\(n\) 异或 \(p\) 得到 \(m\)。

\(m\) 异或 \(x\) 得到 \(q\)。

然后你利用这个 \(q\) 就可以消掉 \(y\) 除最后一位上的1,也就是 \(x\) 最高位上的1,这样就可以消掉一个1,不断重复此过程即可。

\[\begin{aligned} &1------1\quad x\\ 1------&10000000000000\quad y\\ 1------&0------1\quad z=x+y\\ 1------0&1------1\quad n=z+y\\ 1------10&00000000000000\quad p=y+y\\ 1&1------1\quad m=n\oplus p\\ 1&00000000000000\quad q=m\oplus x\\ \end{aligned} \]

code
#include<bits/stdc++.h>
using namespace std;
const long long M=1e5+10;
long long n,cnt;
struct abc{
	long long op,x,y;
}da[M];
long long solve(long long x){
	long long s=(x>>1),y=x;
	while(s){
		da[++cnt].op=1; da[cnt].x=y; da[cnt].y=y;
		y<<=1,s>>=1;
	}
	long long z=(x^y);
	da[++cnt].op=2; da[cnt].x=x; da[cnt].y=y;
	long long t=z+y;
	da[++cnt].op=1; da[cnt].x=z; da[cnt].y=y;
	long long p=y+y;
	da[++cnt].op=1; da[cnt].x=y; da[cnt].y=y;
	long long e=(t^p);
	da[++cnt].op=2; da[cnt].x=t; da[cnt].y=p;
	long long q=(e^x);
	da[++cnt].op=2; da[cnt].x=e; da[cnt].y=x;
	while(y!=(y&(-y))){
		if(y&q){
			da[++cnt].op=2; da[cnt].x=y; da[cnt].y=q;
			y=y^q;
		}
		da[++cnt].op=1; da[cnt].x=q; da[cnt].y=q;
		q=q<<1;
	}
	da[++cnt].op=2; da[cnt].x=y; da[cnt].y=x;
	return y^x;
}
int main(){
	scanf("%lld",&n);
	while(n!=1){
		n=solve(n);
	}
	printf("%lld\n",cnt);
	for(long long i=1;i<=cnt;i++){
		printf("%lld %lld %lld\n",da[i].op,da[i].x,da[i].y);
	}
	return 0;
}

C. 有趣的区间问题

一个类似 \(CDQ\) 分治的做法,对于每个区间,最大值和最小值的位置可以在中点左边也可以是右边,所以一共有四种情况。

  • 最大值最小值都在左边:用一个指针维护右区间的位置即可
  • 最大值最小值都在右边:同上
  • 最大值在左最小值在右:用一个桶存 \(popcount\) 的值,对于每一个最大值,找出右边最大值小于最小值的位置统计答案
  • 最大值在右最小值在左:扩展时一个用 \(\leq\),一个用 \(<\),其余同上
code
#include<bits/stdc++.h>
using namespace std;
const long long M=1e6+10;
struct abc{
    long long id1,id2;
}da[M];
long long n,ans;
long long a[M],num[M];
long long t[70];
inline long long read(){
    long long 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-'0';
        ch=getchar();
    }
    return x*f;
}
inline long long lowbit(long long x){
    return x&(-x);
}
inline long long getnum(long long x){
    long long now=x,num=0;
    while(now){
        now-=lowbit(now);
        num++;
    }
    return num;
}
inline void clear(){
    for(int i=0;i<=65;i++){
        t[i]=0;
    }
    return;
}
void solve(long long l,long long r){
    if(l==r){
        ans++;
        return;
    }
    long long mid=l+r>>1;
    solve(l,mid); solve(mid+1,r);
    da[mid].id1=da[mid].id2=mid;
    for(long long i=mid-1;i>=l;i--){
        da[i].id1=a[da[i+1].id1]>a[i]?da[i+1].id1:i;
        da[i].id2=a[da[i+1].id2]<a[i]?da[i+1].id2:i;
    }
    da[mid+1].id1=da[mid+1].id2=mid+1;
    for(long long i=mid+2;i<=r;i++){
        da[i].id1=a[da[i-1].id1]>a[i]?da[i-1].id1:i;
        da[i].id2=a[da[i-1].id2]<a[i]?da[i-1].id2:i;
    }
    long long j=mid+1;
    for(long long i=mid;i>=l;i--){
        while(j<=r&&a[da[j].id2]>=a[da[i].id2]&&a[da[j].id1]<=a[da[i].id1]){
            j++;
        }
        if(num[da[i].id1]==num[da[i].id2]){
            ans+=j-1-mid;
        }
    }
    long long i=mid;
    for(long long j=mid+1;j<=r;j++){
        while(i>=l&&a[da[i].id2]>=a[da[j].id2]&&a[da[i].id1]<=a[da[j].id1]){
            i--;
        }
        if(num[da[j].id1]==num[da[j].id2]){
            ans+=mid-i;
        }
    }
    clear();
    j=mid+1;
    long long k=mid+1;
    for(long long i=mid;i>=l;i--){
        while(j<=r&&a[da[j].id1]<=a[da[i].id1]){
            t[num[da[j].id2]]++;
            j++;
        }
        while(k<j&&a[da[k].id2]>=a[da[i].id2]){
            t[num[da[k].id2]]--;
            k++;
        }
        ans+=t[num[da[i].id1]];
    }
    clear();
    i=k=mid;
    for(long long j=mid+1;j<=r;j++){
        while(i>=l&&a[da[i].id1]<a[da[j].id1]){
            t[num[da[i].id2]]++;
            i--;
        }
        while(k>i&&a[da[k].id2]>a[da[j].id2]){
            t[num[da[k].id2]]--;
            k--;
        }
        ans+=t[num[da[j].id1]];
    }
}
int main(){
    n=read();
    for(long long i=1;i<=n;i++){
        a[i]=read();
        num[i]=getnum(a[i]);
    }
    solve(1,n);
    cout<<ans<<'\n';
	return 0;
}

D. 无聊的卡牌问题

由于一次拿三张牌,所以我们将三个一组进行捆绑,利用一个栈实现。

可以发现,一些牌的选择是有先后顺序的,所以可以进行拓扑排序,每次拿对其他牌限制多的即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int M=210;
struct abc{
    int x,y,z;
}da[M<<1];
int n,num,top,cnt1,cnt2,op;
int st[M<<3],in[M<<1],out[M<<1];
bool z[M<<3],zz[M<<1];
vector<int>h[M<<1];
priority_queue<pair<int,int>,vector<pair<int,int> >,less<pair<int,int> > >p,q;
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-'0';
        ch=getchar();
    }
    return x*f;
}
int main(){
    n=read(); num=n<<1;
    for(int i=1;i<=n*3;i++){
        int a=read();
        z[a]=1;
    }
    for(int i=1;i<=n*6;i++){
        if(top>=2&&z[i]&&z[st[top]]&&z[st[top-1]]){
            da[++cnt1]=(abc){st[top-1],st[top],i};
            top-=2;
        }
        else if(top>=2&&!z[i]&&!z[st[top]]&&!z[st[top-1]]){
            ++cnt2;
            da[n+cnt2]=(abc){st[top-1],st[top],i};
            top-=2;
        }
        else {
            st[++top]=i;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=n+1;j<=n+n;j++){
            if(da[i].x<da[j].x&&da[j].z<da[i].z){
                h[j].push_back(i);
                in[i]++; out[j]++;
            }
            if(da[j].x<da[i].x&&da[i].z<da[j].z){
                h[i].push_back(j);
                in[j]++; out[i]++;
            }
        }
    }
    for(int i=1;i<=(n<<1);i++){
        if(in[i]==0){
            if(i<=n){
                p.push(make_pair(out[i],i));
            }
            else {
                q.push(make_pair(out[i],i));
            }
        }
    }
    while(num){
        pair<int,int> x;
        if(op==0){
            x=p.top();
            p.pop();
        }
        else {
            x=q.top();
            q.pop();
        }
        if(zz[x.second]){
            continue;
        }
        zz[x.second]=1;
        cout<<da[x.second].x<<' '<<da[x.second].y<<' '<<da[x.second].z<<'\n';
        num--;
        for(int i=0;i<h[x.second].size();i++){
            int y=h[x.second][i];
            in[y]--;
        }
        for(int i=1;i<=(n<<1);i++){
            if(zz[i]==0&&in[i]==0){
                if(i<=n){
                    p.push(make_pair(out[i],i));
                }
                else {
                    q.push(make_pair(out[i],i));
                }
            }
        }
        op=op^1;
    }
    return 0;
}

标签:cnt,top,id2,long,da,&&,CSP,模拟
From: https://www.cnblogs.com/Airposs/p/17764565.html

相关文章

  • 10.14模拟赛
    我觉得这个不要叫作赛后总结了,改成挂分日报吧。(T1虽然很离谱11:40才修改题面,然后11:55结束考试,但是虽然一眼出了正解(就是很简单的一个二分),但是没有开double((((直接挂了,然后读入还写错了。(((尬((T2一个二阶前缀和和二阶差分,酸菜鱼还不会这个怎么用,一会儿大概会更新一个学习笔记......
  • 普冉PY32系列(八) GPIO模拟和硬件SPI方式驱动无线收发芯片XN297LBW
    目录普冉PY32系列(一)PY32F0系列32位CortexM0+MCU简介普冉PY32系列(二)UbuntuGCCToolchain和VSCode开发环境普冉PY32系列(三)PY32F002A资源实测-这个型号不简单普冉PY32系列(四)PY32F002A/003/030的时钟设置普冉PY32系列(五)使用JLinkRTT代替串口输出日志普冉P......
  • 10.14 模拟赛小记
    传送门感觉我已经是半个废人了。A.P1118[USACO06FEB]BackwardDigitSumsG想到的是预处理杨辉三角,然后dfs找。我的预处理写的三维。原因是听大家打键盘的声音太吵了(指机械键盘),然后就不会写二维的了。然后只会写三维的。然后就被同学嘲讽为什么不写二维的。据说next_pe......
  • [CSP-S 2022] 假期计划
    [CSP-S2022]假期计划题目传送门题目大意给定一个$n\leq2500,m\leq10000$的无向图,有点权。求一条点权和最大的路径$1\toA\toB\toC\toD\to1$,满足:$A,B,C,D$均不为$1$,且互不相同;每一段路径上经过的点的数量小于等于$k$。题目分析不难想到要通过bfs预处理出......
  • [CSP-S 2022] 策略游戏
    [CSP-S2022]策略游戏题目传送门题目分析本文中A和B分别代表小L和小Q,而原题中的$A$,$B$两个数组在本题中分别用$a$和$b$表示。矩阵这个描述就是障眼法。翻译一下题目:A在$a[l_1\cdotsr_1]$中选择一个$x$,然后B在$b[l_2\cdotsr_2]$中选择一个$y$,分数......
  • 模拟集成电路设计系列博客——2.3 电流镜放大器
    模拟集成电路设计2.3电流镜放大器2.3电流镜放大器另一个在驱动片上容性负载时常用的放大器是电流镜放大器,其简化图如下所示:通过使用高输出阻抗的合理的电流镜结构,能够使得整体增益变得相当可观。下图展示了一个电流镜放大器的细节结构:整体的传输函数可很近似于单极点系统......
  • CSP2023 游记
    \(\mathrm{Day\-?}\)模拟赛场场降智破防垫底,但是都是大于*1900的史诗级难题,到时候考试的时候肯定不会这么难的呀!\(\mathrm{Day\1}\)拿到题,解压密码是yuanshenqidong。发现T1是给你两个整数,问他们的乘积。我想了想说这个题不难啊,相当于就是说\(n\timesm\)的网格里......
  • CSP2023 赛前集训总结
    2023.09.18T1刘谋题面描述现在,反抗军首领大司马交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及骚猪帝国打击的星球顺序,以尽量快的速度求出每一次打击之后反抗军占据的星球的连通块的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则这两个星球在同一......
  • 考场(CSP模拟55联测17)
    T1签到题?也许存在性质:若一个点作为中点,则它永远不会被换?目测挺对,因为它(设为\(x\))前面的数在换过以后会比它小,而。。然后就挺错的。假了。不对不对,前面的数在换过以后会比它小,若想让\(x\)被换,那么一定要保证前面的数比\(x\)大,一定不可能,所以真了!!!发现策略,若一个序列可以......
  • [刷题笔记] Luogu P5658 [CSP-S 2019] 括号树
    Description给定一棵树,树的每个节点都有一个左括号或者右括号,求从根节点到每个点简单路径上的括号序列上合法的子括号序列数。Analysis显然树形dp。考虑如何设计状态,定义\(f_i\)表示从root到\(i\)节点的字串合法数量。考虑转移,如果当前的括号为左括号,我们无法和前面的......