首页 > 其他分享 >2022SWJTU寒假选拔赛1题解

2022SWJTU寒假选拔赛1题解

时间:2023-01-11 23:23:04浏览次数:56  
标签:int 题解 2022SWJTU 元素 矩阵 小幻 选拔赛 sum 坐标

目录

A - 马宝の皮颜矩阵

Description

给定矩阵\(a[N][M],1\le N·M\le1e5,1\le a[i][j] \le 1e5\),求所有相同元素的曼哈顿距离和\(X\)

Input

给出矩阵的行列\(n,m\)

给出矩阵所愿元素\(a[i][j]\)

Solution

此题难在N,M的范围比较飘,比如1*1e5(test8)

暴力算法是:记录每种元素的所有坐标,在遍历元素坐标数组或遍历矩阵位置时,曼哈顿距离和即为当前坐标与所有前驱坐标的曼哈顿距离和

复杂度\(O(nm*cnt)\),tle on test 9 \((5*20000*multi(6146))\)

//遍历矩阵,每个坐标与所有前驱产生权值。tle on test 9
for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{			
			for(auto it:mey[a[i][j]])
			{
				X+=abs(i-it.x)+abs(j-it.y);
			}
			mey[a[i][j]].push_back(Pair(i,j));
		}
	}

假优化是:x轴y轴离散化,统计每个元素在每行每列出现的次数,离散化求出曼哈顿距离。

假优化中,离散化后是\(C_n^2\)的方法来两行/两列间的权值。

乍一看是不错的优化,处理有大量元素重复的数据会快很多。

但是,复杂度\(O(count*(n^2+m^2))\)tle on test8\(1*1e5\)

//遍历元素的坐标数组
for(int i=1;i<=1e5;i++)
	{
        //vec[i]为i元素在矩阵中的各个坐标。
		if(vec[i].size()==0) continue;
		vector<int> row(n,0);
		vector<int> col(m,0);
        //统计在各行各列的词频
		for(auto it:vec[i])
		{
			row[it.first]++;
			col[it.second]++;
		}
        //每次计算出两行/两列间这size*size对元素的曼哈顿距离和
		for(int j=0;j<row.size();j++)
		{
			for(int k=j+1;k<row.size();k++) X+=row[j]*row[k]*(k-j);
		}
		
		for(int j=0;j<col.size();j++)
		{
			for(int k=j+1;k<col.size();k++) X+=col[j]*col[k]*(k-j);
		}
	}

这个不固定形状的\(1\le N·M\le1e5\)说明本题不能用二维的方式来求曼哈顿距离。

离散化的思想是正确的,此外还需二维降一维的思想。

结合一下暴力和假优化,有以下point:

1.不同值的元素的曼哈顿距离和是独立的

2.同一元素的坐标中,x和y的贡献是独立的。

考查某个元素在某一轴的坐标vector,这个元素在这个方向的权和是这个数组\(C^2_n\)元素间差值的绝对值的和

不维护矩阵,维护每种元素的各个坐标,x轴和y轴坐标可以分开维护。

\(Ans=\sum Elem.(xval +yval) ,val=\sum a[j]-a[i]\)

优化可以发生在\(val=\sum a[j]-a[i]\),若数组有序,val不必用两层for\(C^2_n\)的方式来求

将这个元素的坐标数组升序排序,在遍历中,每新入一个坐标,都会与前面的所有坐标产生权值,总权值:

\(\sum a[j]-a[i]=cnt*a[j]-\sum a[i]\),cnt即为\(a[j]\)的序号,\(\sum a[i]\)即为前缀和

Code

#include<bits/stdc++.h>
using namespace std;
using ll= long long;
const int N=1e5+5;
vector<int> x[N];
vector<int> y[N];
ll X=0;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	int n,m;
	cin>>n>>m;
	//维护出元素a的坐标vector
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			int a;cin>>a;
		    x[a].push_back(i);
		    y[a].push_back(j); 
		}
		
	}	
	for(int i=1;i<=1e5;i++)
	{
		if(x[i].empty()) continue;
		//升序排序
		sort(x[i].begin(),x[i].end());		
		ll xsum=0,cnt=0;
        //一次求出it这个坐标与所有前驱坐标的组合权值。
		for(auto it:x[i])
		{
		
			X+=1ll*cnt*it-xsum;
			cnt++;
			xsum+=it;
		}
	}
	for(int i=1;i<=1e5;i++)
	{
		if(y[i].empty()) continue;
		
		sort(y[i].begin(),y[i].end());		
		ll ysum=0,cnt=0;
		for(auto it:y[i])
		{
			X+=1ll*cnt*it-ysum;
			cnt++;
			ysum+=it;
		}
	}
	
    cout<<X;
    return 0;
}

I - 小幻777

Description

小幻同学新学了一个魔法,每次消耗一点1点体力可以变换某个数的任意一位数的大小,但是不能变换出前导0.

比如 344->244, 但是不能044

小幻同学喜欢7,问给你一个数,在最少消耗体力的情况下,输出你变换后的数能够被7整除

如果你用暴力做法,那小幻同学不是很认可  ̄へ ̄

Solution

可以给出的是,只修改个位数就能整除7了,对于数x,余项(x%7),x,个位较大,就减x%7,各位较小,就加7-x%7。

Code

不贴

J - 小幻考考你

Description

小幻给出一个序列A,长度为n, 0-n-1的数都会出现在队列A里面,且出现一次, 你现在可以用你聪明的小脑瓜对这个队列排序,使得 $MAX (ai\oplus a(i+1)) $的值最小

Solution

遇到位运算,我们可以考虑二进制一位一位的思考
发现对于位数最多的数, 无论他们整么放置, 最后都会产生一个^出来的数有这么多位
于是就让这个^产生出的最大数为 100000..(二进制下)
于是利用0把这些数分开, 一边是 数的位数是小于 最高位数的, 一边都是最高位数, 当然和0挨着的 要是 10000..(二进制下)


当然,如果你观察能力够强的话,可以直接通过样例来找规律, 这也是一种方法 ——某幻老师

对\(MAX(ai\oplus a(i+1))\)有非常大影响的是那些位数最多的数,形如0000-0111,1000,1001这段序列的异或最小也是1___了,首位是消不掉的(考查1000,右侧可以放形如1__1,左侧捏...),考查低三位000,放任何数与其异或都没有意义。

所以只能在左侧放0,然后期望这个1000...就是最小的最大值。

这是非常容易达成的,甚至只需要按自然序排列就行,例如,形如n=15的构造策略:

0001,0010,0011,0100,0101,0110,0111,!!0000,1000!!,1001,1010,1011,1100,1101,1111

把位数高的那一坨数字都排在一起,那一块的最高位的异或就都是零了(较小的),分界发生在0000,1000,这就是所能构造出来的最小的最大值。

Code

void solve(int x)
{
    if(x==2) {cout<<"0 1\n";return;}
    int m=1;
    //找到离(x-1)最近的(1000...)
    while(m<=(x-1)) m<<=1;
	m>>=1;
    for(int i=1;i<x;i++)
    {
      if(i==m) cout<<0<<" ";
      cout<<i<<" ";
    }
}

位运算请贪心地自高位向低位思考

[友链蓝桥:选数异或,异或博弈](蓝桥备赛 - 题单 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))

标签:int,题解,2022SWJTU,元素,矩阵,小幻,选拔赛,sum,坐标
From: https://www.cnblogs.com/yceachan/p/17045160.html

相关文章

  • 洛谷P6599 「EZEC-2」异或【题解】
    题目大意有\(T\)组数据,每组数据给定两个\(l,n\in\mathbb{N*}\),构造一个长为\(l\),每个元素不超过\(n\)的数组令他为\(a\),要使\[\sum_{i=1}^l\sum_{j=1}^{i-1}a_i\oplu......
  • SYUCT acm第八次限时训练题解
    SYUCTacm第八次限时训练题解MakeitBeautiful题目大意code#include<bits/stdc++.h>usingnamespacestd;constintN=100;inta[N];intb[N];voidsolve()......
  • 【题解】AT3611 Tree MST
    喝,长大了......
  • CF 1581B Diameter of Graph 题解
    题面:给定n个顶点,m条边,任意两点并且最大距离小于k,两个顶点只能连一条边,询问是否能构造出这样的图型思路:1.n=1时进行特判,只有k>1时成立2.m=n(n-1)/2时,是完全图,只有k......
  • 【题解】CF1268C K Integers
    萌新不懂就问,这是什么时代的题啊???思路trick题。首先根据trick可知:先将\([1,k]\)中的数聚在一起再排序是最优的。排序的花费是逆序对数,所以现在的问题是求把\([1,......
  • Codeforces 1278 F Cards 增强版 题解 (斯特林数,推式子)
    原题链接增强版链接增强版中k=1e7为啥网上题解的式子都那么长啊.jpg首先令\(p=\frac1m\)。求某个数的次幂的题通常都是无脑转下降幂:\(x^k=\sum_{i=0}^kS_2(k,i)x^{\u......
  • SOJ1711 题解
    题意给定\(n\)个在数轴的区间\([l_1,r_1],[l_2,r_2],...,[l_n,r_n]\)。定义\(I(x)\)为所有包含\([x,x+1]\)的区间形成的集合,即\(I(x)=\{k\mid[x,x+1]\subsete......
  • 搭建k8s集群初始化master节点 kubeadm init 遇到问题解决
    搭建k8s集群时遇到的问题一记,自己找了很久解决方案,也看到有些人提出类似问题后不了了之,于是发出来给网络做一次贡献kubeadminit报错”unknownserviceruntime.v1al......
  • CF850B Arpa and a list of numbers 题解 枚举
    题目链接:https://codeforces.com/problemset/problem/850/B题目大意我们定义一个数列是”坏的数列”当且仅当这个数列不为空且数列中所有元素的最大公约数为\(1\)。......
  • 题解 BZOJ3622【已经没有什么好害怕的了】
    前置知识:二项式反演problem两个\(n\leq2000\)的数组\(A,B\),元素互不相同,求有多少种将\(A,B\)配对的方法使得\(A>B\)的恰好有\(k\)对。题目改过,但是这一步转换......