首页 > 其他分享 >10月4日 CSP-S 模拟

10月4日 CSP-S 模拟

时间:2023-10-04 16:45:34浏览次数:35  
标签:10 f2 排列 f1 int 序列 CSP 模拟 逆序

10月4日 CSP-S 模拟赛总结

2457

题目大意

给定一个长度为 \(n\) 的排列 \(A\),问交换两数的位置,最多能使逆序对的数量减少多少

思路

50 pts(\(n^2\))

开两个二维数组, f1[i][j] 表示 \(i\) 与 \(j\) 互换位置时对于 \(i\) 减少的逆序对数量(也可以是增加),f2[i][j]f1[i][j] 同理,不过是对于 \(j\) 来说的。

接下来考虑转移,对于 f1[i][j],如果 \(a[i]>[j]\),那么 \(f1[i][j]=f1[i][j-1]+1\),否则,\(f1[i][j]=f1[i][j-1]-1\)。f2 同理。

Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e6+1;
int n,ans;
bool flag;
int a[maxn];
int f1[1001][1001];//i减少的逆序对 
int f2[1001][1001];//j减少的逆序对 
signed main()
{
	//freopen("2457.in","r",stdin);
	//freopen("2457.out","w",stdout);
	std::ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		cin>>a[i];
		if(a[i]<a[i-1])flag=1;
	}
	if(!flag)
	{
		cout<<0<<endl;
		return 0;
	}
	for(int i=1;i<=n;++i)
		for(int j=i+1;j<=n;++j)
		{
			if(a[i]>a[j])
				f1[i][j]=f1[i][j-1]+1;
			else
				f1[i][j]=f1[i][j-1]-1;
		}
	for(int i=n;i>=1;--i)
		for(int j=i+1;j<=n;++j)
		{
			if(a[i]>a[j])
				f2[i][j]=f2[i+1][j]+1;
			else
				f2[i][j]=f2[i+1][j]-1;
		}
	for(int i=1;i<=n;++i)
		for(int j=i+1;j<=n;++j)
			ans=max(ans,f1[i][j]+f2[i][j]);
	cout<<ans-1<<endl;
	return  0;
}

100 pts

不会

2458

题目大意

给定一个长为 \(n\) 的序列 ,可以进行下述操作:选择一个下标 \(i\),将 \((a_i,a_{i+1},a_{i+2})\) 替换成
\((a_{i+1},a_{i+2},a_i)\)。
构造一个长度不超过 \(n^2\) 的操作序列,使得操作完毕后,序列升序排列。

思路

先考虑原序列是一个排列的情况。

我们先将元素 \(1\) 换到最前面,再将元素 \(2\) 换到第二位……直到 \(n-2\) 也这样完成。于是,现在序列要么形如 \(1,2,...,n-2,n-1,n\),要么形如 \(1,2,...,n-2,n,n-1\)。前一种已经完成了,那后一种怎么办呢?

其实可以证明,如果此时出现了后一种情况,那么是无解的。考虑对排列定义“排列的符号”:\((-1)^{逆序对的数量}\)。当交换了相邻两个数之后,因为逆序对数要么增加一,要么减少一,所以无论如何“排列的符号”都会变号。(事实上,我们可以拓展这个结论,在一个排列中交换任意两个数,排列的符号都会发生改变)

而题面中的操作就相当于做了两次相邻元素交换,于是在进行一次题面操作后,排列的符号保持不变。所以,如果出现了 \(1,2,...,n-2,n,n-1\) 这种情况,那说明初始排列的符号和目标排列的符号是不同的,于是无解。

那么如果原序列不是一个排列呢?我们不妨将其转化成一个排列。如果有相同的元素,我们不妨随便钦定一个它们之间的大小关系,然后再进行离散化,这样原序列就变成一个排列了(直接随机排列)。可要是这样变化后无解,不代表原序列就无解。但是,我们可以挑出一对相同的元素,反转它们被钦定的大小关系。下面是一个例子。

比如,原序列是 \(2,3,3,3\),可能变化出来的序列是 \(1,2,4,3\),这是无解的。但是,我们可以交换两个“大小相邻”的 3 的顺序,变成 \(1,2,3,4\),这样就是有解的了。

因此,如果原序列没有相同元素,那么离散化后使用对于排列的算法即可。如果有相同元素,那么仍然可以把它转化成排列的情况,并且可以转化成两个符号不同的排列,而其中一个必定有解,也套用上述算法即可。

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e3+1;
int n;
bool flag;
int a[maxn];
int b[maxn];
vector<int> ans;
inline void change(int x)
{
	ans.push_back(x);
	swap(b[x],b[x+1]);
	swap(b[x+1],b[x+2]);
}
inline bool solve()
{
	ans.clear();
	for(int i=1;i<=n;++i)
		b[i]=a[i];
	for(int i=1;i<=n-2;++i)
	{
		int maxx=b[1];
		vector<int> box;
		for(int j=1;j<=n-i+1;++j)
		{
			if(maxx<b[j])
			{
				maxx=b[j];
				box.clear();
				box.push_back(j);
			}
			else if(maxx==b[j])
				box.push_back(j);
		}
		srand(time(0));
		random_shuffle(box.begin(),box.end());
		int x=box[0];
		while(x<=n-i-1)
		{
			change(x);
			x+=2;
		}
		if(x==n-i)
		{
			change(x-1);
			change(x-1);
		}
	}
	if(b[1]>b[2])
		return false;
	return true;
}
signed main()
{
	std::ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;++i)cin>>a[i];
	if(n<=2)
	{
		if(n==1)
			cout<<0<<endl;
		if(n==2)
		{
			if(a[1]<=a[2])
				cout<<0<<endl;
			else
				cout<<-1<<endl;
		}
		return 0;
	}
	for(int i=1;i<=10;++i)
	{
		flag=solve()?true:false;
		if(flag)break;
	}
	
	if(!flag)
	{
		cout<<-1<<endl;
		return 0;
	}
	cout<<ans.size()<<endl;
	for(int i=0;i<ans.size();++i)
		cout<<ans[i]<<' ';
	return 0;
}

2459

2460

题目大意

给定 \(n\),\(m\) 保证 \(m\le n\),计算满足下面条件的排列个数:

长度为
不存在相邻两个数和为 \(m\) 或 \(m+1\)

对 \(10^9+7\) 取模。

标签:10,f2,排列,f1,int,序列,CSP,模拟,逆序
From: https://www.cnblogs.com/PenguinChen/p/17742426.html

相关文章

  • c语言代码练习10(改进)
    #define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>#include<string.h>#include<math.h>intmain(){intn=0;inti=0;printf("请输入你想要判断的数字:");scanf("%d",&n);for(i=2;i<sqrt(n)......
  • 2023-10-04:用go语言,现有一棵无向、无根的树,树中有 n 个节点,按从 0 到 n - 1 编号 给你
    2023-10-04:用go语言,现有一棵无向、无根的树,树中有n个节点,按从0到n-1编号给你一个整数n和一个长度为n-1的二维整数数组edges,其中edges[i]=[ai,bi]表示树中节点ai和bi之间存在一条边。每个节点都关联一个价格。给你一个整数数组price,其中price[i]是第i......
  • c语言代码练习10
    \\判断输入的数字是否为素数#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>#include<string.h>intmain(){intn=0;inti=0;printf("请输入你想要判断的数字:");scanf("%d",&n);for(i=2;i<n;i++){......
  • 2023-10-04:用go语言,现有一棵无向、无根的树,树中有 n 个节点,按从 0 到 n - 1 编号 给你
    2023-10-04:用go语言,现有一棵无向、无根的树,树中有n个节点,按从0到n-1编号给你一个整数n和一个长度为n-1的二维整数数组edges,其中edges[i]=[ai,bi]表示树中节点ai和bi之间存在一条边。每个节点都关联一个价格。给你一个整数数组price,其中price[i]是......
  • 2023.10.4测试
    T1最短路T2欧拉函数给定常数\(B\),\(T\)组测试数据,每次给定\(l,r\),求\[\sum_{x=l}^r\varphi^{(\max_{i=1}^x\varphi(x)-B)}(x)\]当\(\max_{i=1}^x\varphi(x)-B\leq0\)时\(\varphi^{(\max_{i=1}^x\varphi(x)-B)}(x)=x\)\(1\leqT\leq10^5\),\(1\leqr,B......
  • Solution -「ARC 106E」Medals
    Desc.  Link.  你有\(n\)个朋友,他们会来你家玩,第\(i\)个人\(1...A_i\)天来玩,然后\(A_i+1...2A_i\)天不来,然后\(2A_i+1...3A_i\)又会来,以此类推;  每天你会选一个来玩的人,给他颁个奖,如果没人来玩,你就不颁奖。  你要给每个人都颁\(K\)个奖,问至少需要多少......
  • Window10安装SQL Server
    一、安装SQLServer1、进入官网根据个人所需下载对应版本即可,本文是基于SQLServer2022Express的安装过程2、下载完毕,运行安装指引程序二、安装访问管理工具SSMS1、点击“安装SSMS”按钮,自动跳转到官网下载页,直接点击下载链接即可2、下载完毕运行安装程序3、安装完成,打......
  • P1054 [NOIP2005 提高组] 等价表达式
    P1054[NOIP2005提高组]等价表达式这个题在计算表达式时可能会出现高次方,比如在某一数据中就出现了2^7^10也就是\(2^{70}\)自然溢出会寄,所以要取模自然溢出\(80\)分ullquick_pow(ullx,ullp){ ullres=1; while(p) { if(p&1)res*=x; p>>=1;......
  • 题解 CF1034C【Region Separation】/ SS221116D【Xiong AK 10 IOI】
    很妙的性质题!全是意识流证明见过吗?problem每次选一个非空边集删掉,谓之曰砍树。砍树后需要满足每个连通块的点权和相同。在一个方案中可以砍很多次树,都要满足砍树后的要求。一共有多少种合法方案呢?\(n\leq10^6,1\leqa_i\leq10^9\)。solution假如我们将树砍成\(k\)个连通......
  • CSP考前
    练习区\(\text{1.指针的使用√}\)\(\text{2.二叉树的遍历:前序、中序、后序√}\)\(\text{3.二叉搜索树的定义和构造√}\)\(\text{4.图的表示与存储:邻接矩阵、邻接表√}\)\(\text{5.搜索√}\)\(\text{6.链表}\)\(\text{7.倍增法(快速幂)}\)\(\text{8.动态规划}\)\(\text{9.......