首页 > 其他分享 >codeforces div_2 936 题解报告

codeforces div_2 936 题解报告

时间:2024-03-23 22:37:08浏览次数:26  
标签:最大数 int 题解 codeforces long pos div times define

codeforces div_2 936 题解报告

比赛链接:https://codeforces.com/contest/1946

A.Median of an Array

做法tag:签到

题目翻译

给定一个长度为\(n\)的数组\(a\),记数组中非降序排列中第\({\lceil \frac n 2 \rceil}\)个数是数组a的中位数。
我们可以以下操作。

  • 选择一个数\(i \in[1,n]\),使\(a_i:=a_i+1\)

问,对于给定的数组,我们至少要作多少次操作,才能使中位数变大。

解法

先对数组排序,设\(j\)是满足\(a_j=a_{\lceil \frac n 2 \rceil}\)的最大整数,子数组\(a[\lceil \frac n 2 \rceil:j]\)的值都相等,我们要使此子数组的每个数都增大才能使中位数增大,也就要操作\(j-\lceil \frac n 2 \rceil +1\)次。

点我查看代码
#include<bits/stdc++.h> 
#define ll long long 
//#define int long long
#define mid ((l+r)>>1)
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
#define inf 0x3f3f3f3f 
typedef int LL;
const signed maxn=(signed)1e6+5;
inline LL Read(){
	char ch=getchar();bool f=0;LL x=0;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')f=1;
	for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
	if(f==1)x=-x;return x;
}
int ar[maxn];
signed main()
	{	 
		LL T=Read();
		while (T--){
			int n=Read();
			for(int i=1;i<=n;++i) ar[i]=Read();
			std::sort(ar+1,ar+1+n);
			int md=(n+1)/2,c=1;
			for(int i=md+1;i<=n;++i){
				if(ar[i]==ar[i-1]) ++c;
				else break;
			}
			printf("%d\n",c);
		}
		return 0;
	}	

B.Maximum Sum

做法tag:贪心

题目翻译

给定一个长度为\(n\)的数组\(a\),我们要对数组做以下操作恰好\(k\)次。

  • 选择一段连续子数组(可以为空,和为\(0\)),记\(sum\)为这一段子数组中所有数的和,将\(sum\)插入到任意我们想插入的位置。

问,\(k\)次操作后数组\(a\)的和的可能的最大值是多少(输出时对\(1e9+7\)取模)。

解法

第一次操作,找到我们能找到的最大\(sum_1\)(找不到正的\(sum_1\)就选空,记\(0\)),然后插入到我们找到的子数组中,第二次的\(sum_2=2\times sum_1\),\(sum_k=2^{k-1} \times sum_1\)。记原数组和是\(sum_a\),最后答案就是$$sum_a+(2^k-1)\times sum_1 $$

点我查看代码
#include<bits/stdc++.h> 
#define ll long long 
//#define int long long
#define mid ((l+r)>>1)
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
#define inf 0x3f3f3f3f 
typedef int LL;
const signed maxn=(signed)1e6+5;
const signed mod=(signed)1e9+7;
inline LL Read(){
	char ch=getchar();bool f=0;LL x=0;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')f=1;
	for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
	if(f==1)x=-x;return x;
}
int add(int a,int b){
	return ((a+=b)>=mod)?a-mod:a;
}
int mul(int x,int y){
	return (ll)x*y%mod;
}
int fpow(int a,int b){
	int ans=1;
	while(b){
		if(b&1) ans=mul(ans,a);
		a=mul(a,a);
		b>>=1;
	}
	return ans;
}
int ar[maxn];
signed main()
	{	 
		LL T=Read();
		while (T--){
			int n=Read(),k=Read();
			for(int i=1;i<=n;++i) ar[i]=Read();
			int sum=0;
			ll mx=0,c=0;
			for(int i=1;i<=n;++i){
				int a=ar[i];
				if(a<0) sum=add(sum,mod+a);
				else sum=add(sum,a);
				c+=a;
				mx=std::max(c,mx);
				if(c<0) c=0;
			}
			mx%=mod;
			sum=add(sum,mod-mx);
			mx=mul(mx,fpow(2,k));
			sum=add(sum,mx);
			printf("%d\n",sum);
		}
		return 0;
	}	

C.Tree Cutting

tag:二分答案,贪心check

题目翻译

给定一棵\(n\)个结点的树,给定一个数\(k(k<n)\),要求删去树上\(k\)条边,要求删边后每个独立的树的大小都不小于\(x\)。问\(x\)最大可以取多少。

解法

\(x\)肯定越小越能实现。考虑二分答案。\(x \in [1,n]\),二分复杂度\(O(\log n)\)。

对于特定\(x\),检查方法如下,随意定一个树根,对树\(dfs\),如果某一个子树大小超过\(x\),就贪心的把子树剪出来,剪出来之后这棵子树的\(siz\)就不会上传给父亲。如果已经剪了\(k\)颗子树出来,也就是已经删去\(k\)条边,不用再剪子树了。最后在是否删去足够的边,并判断原树被剪去子树后大小(记为\(siz_0\))是否满足\(siz_0>=x\)。

  • tips:不用考虑要不要挑小的子树删,因为当可以选择的时候,也就是有两颗子树\(siz>=x\),哪一颗留在原树上都能满足\(siz_0>=x\)。
点我查看代码
#include<bits/stdc++.h> 
#define ll long long 
//#define int long long
#define mid ((l+r)>>1)
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
#define inf 0x3f3f3f3f 
typedef int LL;
const signed maxn=(signed)1e6+5;
inline LL Read(){
	char ch=getchar();bool f=0;LL x=0;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')f=1;
	for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
	if(f==1)x=-x;return x;
}
int n,k,x;
struct Edge{
	int to,nxt;
}edge[maxn<<1];
int head[maxn],ecnt;
void Adde(int u,int v){
	edge[++ecnt]=(Edge){v,head[u]};
	head[u]=ecnt;
}
int ans;
int siz[maxn];
void dfs(int u,int Fa){
	siz[u]=1;
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(v==Fa) continue;
		dfs(v,u);
		if(siz[v]>=x&&ans<k) ++ans;
		else siz[u]+=siz[v];
	}
	if(u==1&&siz[1]<x) ans=0;
}
signed main()
	{	 
		LL T=Read();
		while (T--){
			n=Read(),k=Read();
			for(int i=1;i<=n;++i) head[i]=0;ecnt=0;
			for(int i=1;i<n;++i){
				int u(Read()),v(Read());
				Adde(u,v),Adde(v,u);
			}
			int l=1,r=n/k;
			while(l<=r){
				x=mid;ans=0;
				dfs(1,0);
				if(ans<k) r=x-1;
				else l=x+1;
			}
			printf("%d\n",r);
		}
		return 0;
	}	

D.Birthday Gift

做法tag:位运算,按位贪心

题目翻译

给定一个数组\(a\)和整数\(x\),我们要给出\(k\)个区间$$[l_1,r_1],[l_2,r_2],...,[l_k,r_k]$$
满足

  1. \(l_1=1,r_k=n\)
  2. \(\forall i\in N,(i\in [1,k-1])\to (l_{i+1}=r_i+1)\)
  3. \[(a_{l_1} \oplus a_{l_1+1}\oplus ... \oplus a_{r_1})|(a_{l_2} \oplus a_{l_2+1}\oplus ... \oplus a_{r_2})|...|(a_{l_k} \oplus a_{l_k+1}\oplus...a_{r_k}) <=x \]

问,\(k\)最大可以取多少,若不存在满足条件的\(k\),输出\(-1\)。

解法

前两个条件就是把数组恰好划分为\(k\)个连续子数组。

先划分为\(n\)个区间,每个区间只有一个数。然后按位由高到低考虑第三个条件。若是或的结果太大,就把一些连续区间异或起来减小结果。我们只关心区间个数,并且我们对区间只有合并操作,我们只记录一个异或和,用一个数(异或和)代表这个区间,最后看看有几个数即可。具体如下。

记目前\(a\)中有\(f\)个数第\(i\)位为\(1\)。

  1. 若\(x\)第\(i\)位为\(0\),\(f\)是奇数,那么异或也不会使奇数个\(1\)变为\(0\),无法满足条件,退出。
  2. 若\(x\)第\(i\)位为\(0\),\(f\)是偶数,那么我们按照就近原则分为\(\frac f 2\)组,每一组两个数和中间所有数合并到一个区间里去。
  3. 若\(x\)第\(i\)位为\(1\),\(f\)是偶数,可以尝试合并区间,这样这一位就是小于关系,可以得到满足条件的答案,但也有可能不合并,这一位双方取等号,看低位会不会有更小的答案。
    所以处理起来就是,尝试合并,更新答案,但是原数组不变,接着去处理低位。

4.若\(x\)第\(i\)位为\(1\),\(f\)是奇数,这一位注定是取等号,所以不做任何处理。看下一位。

这样基本就完成了,但是一直把相等的情况留给低位处理,没有实际处理完全相等的情况。所以在最低位要特殊处理。

当\(i=0\),也就是最低位的处理逻辑

  1. 若\(x\)第\(i\)位为\(0\),\(f\)是奇数,那么异或也不会使奇数个\(1\)变为\(0\),无法满足条件,退出。
  2. 若\(x\)第\(i\)位为\(0\),\(f\)是偶数,合并完后记录答案。
  3. 若\(x\)第\(i\)位为\(1\),无需合并直接记录答案。

这样就彻底完结了。

点我查看代码
#include<bits/stdc++.h> 
#define ll long long 
//#define int long long
#define mid ((l+r)>>1)
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
#define inf 0x3f3f3f3f 
typedef int LL;
const signed maxn=(signed)1e6+5;
inline LL Read(){
	char ch=getchar();bool f=0;LL x=0;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')f=1;
	for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
	if(f==1)x=-x;return x;
}
std::vector<int> arr1,arr2;
int n,x;
int merge(int bit,bool f){//f=1 true merge,f=0 do a test
	int val=0,newn=0;
	int bound=1<<bit;
	for(int i=1;i<=n;++i){
		val^=arr1[i];
		if(val<bound){
			arr2[++newn]=val;val=0;
		}
	}
	if(f) std::swap(arr1,arr2);
	return newn;
}
signed main()
	{	 
		LL T=Read();
		while (T--){
			n=Read(),x=Read();
			arr1.resize(n+5);
			arr2.resize(n+5);
			for(int i=1;i<=n;++i) arr1[i]=Read();
			int ans=-1;
			for(int i=29;~i;--i){
				int f=0;
				bool xf=(x>>i)&1;
				for(int j=1;j<=n;++j)
					if((arr1[j]>>i)&1)	++f;
				if(i==0){
					if(xf) ans=std::max(ans,n);
					else if(f%2==0)
							ans=std::max(ans,merge(i,0));
					else break;
				}
				else if(f%2==1&&xf==0) break;
				else if(f%2==0&&xf) ans=std::max(ans,merge(i,0));
				else if(f%2==0&&xf==0)	n=merge(i,1);
				for(int j=1;j<=n;++j){
					if((arr1[j]>>i)&1) arr1[j]-=(1<<i);
				}
			}
			printf("%d\n",ans);
		}
		return 0;
	}	

E.Girl Permutation

做法tag:组合数,分治?

题目翻译

给定一个数\(n\),有一个未知的长度为\(n\)的排列,排列就是\(1\) ~ \(n\)中每个数在排列中恰好出现一次。
给出两个定义

  1. 前缀最大数。当\(\forall j,(1<=j<i) \to a_j<a_i\),称\(a_i\)是前缀最大数。
  2. 后缀最大数。当\(\forall j,(i<j<=n) \to a_j<a_i\),称\(a_i\)是后缀最大数。

给出未知排列前缀最大数的个数\(m_1\)和所有的前缀最大数的下标(升序给出),还有前后缀最大数的个数\(m_2\)和所有的后缀最大数的下标(升序给出)。

问,有多少中排列可能是未知排列,输出个数(对\(1e9+7\)取模)。

解法

用数组\(ar\)记录前缀最大数下标,\(br\)记录后缀最大数下标。
一个显然的性质,最后一个前缀最大数和后缀最大数是最大的数\(n\)。也同时要求下标数组\(ar_{m1}=br_1\)。还有\(ar_1=1,br_{m2}=n\)
再先给出一个结论:我们只关心数之间的相对大小,绝对大小无意义,又因为数字两两不同,所以数字数量相同,对于同一种题目条件,得到的个数是一致的。

这说明了什么呢?
一个独立的区间,需要的数字数量是固定的,如果我们能够把全局前缀最大和全局后缀最大给改成区间条件,那么这个区间就可以是一个独立问题。我们记录区间左右端点是\(l,r\),排列个数用\(solve(l,r)\)表示。

那么,对于其他数字而言,\(n\)是不可跨越的大山,\(n\)左端的区间和右端的区间互相独立,左区间不会再出现后缀最大数,左区间要满足的全局前缀最大数也可以转化为区间内的前缀最大(后面的数不影响前缀)。左区间可以成为独立问题。右区间同理。
假设\(n\)被放在了\(pos_n\)s上。那么$$solve(1,n)=C \dbinom{pos_n-1}{n-1}\times solve(1,pos_n-1)\times(pos_n+1,n)$$
组合数\(C \dbinom{pos_n-1}{n-1}\)就是把数分成特定大小的两组的可能数。
对于区间\([1,pos_n-1]\),这是一个只需要满足一些前缀最大的区间。假设其中最大的数是\(x\),\(x\)就是最大的,最后面的那个前缀最大数,位置记作\(pos_x\),对于\([1,pos_x-1]\)仍然是只有前缀最大数的区间,可以递归求解,直到\([1,1]\)返回\(1\)。对于\([pos_x+1,pos_n-1]\),这个区间怎样都不会出前缀最大和后缀最大,也不需要出,随意排序即可。

\[solve(1,pos_n-1)=C \dbinom{pos_n-pos_x-1}{pos_n-1}\times solve(1,pos_x-1)\times solve(pos_x+1,pos_n-1) \]

又\(solve(pos_x+1,pos_n-1)=(pos_n-pos_x-1)!\)
所以

\[solve(1,pos_n-1)=A \dbinom{pos_n-pos_x-1}{pos_n-1}\times solve(1,pos_x-1) \]

之后递归求解即可。后缀也同理。
放代码(我写的是非递归版本,只要搞清楚每一个前缀最大数的下标的贡献即可)。

点我查看代码
#include<bits/stdc++.h> 
#define ll long long 
//#define int long long
#define mid ((l+r)>>1)
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
#define inf 0x3f3f3f3f 
typedef int LL;
const signed maxn=(signed)1e6+5;
const signed mod=1e9+7;
inline LL Read(){
	char ch=getchar();bool f=0;LL x=0;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')f=1;
	for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
	if(f==1)x=-x;return x;
}
int jc[maxn],inv[maxn];
int mul(int x,int y){
	return (ll)x*y%mod;
}
int A(int m,int n){
	//printf("m=%d n=%d\n",m,n);
	return mul(jc[m],inv[m-n]);
}
int C(int m,int n){
	//printf("m=%d n=%d\n",m,n);
	return mul(jc[m],mul(inv[m-n],inv[n]));
}
int fpow(int a,int b){
	int ans=1;
	while(b){
		if(b&1) ans=mul(ans,a);
		b>>=1;a=mul(a,a);
	}
	return ans;
}
int ar[maxn],br[maxn];
signed main()
	{	 
		int mx=3e5;
		jc[0]=inv[0]=1;
		for(int i=1;i<=mx;++i) jc[i]=mul(jc[i-1],i);
		inv[mx]=fpow(jc[mx],mod-2);
		for(int i=mx-1;i;--i) inv[i]=mul(inv[i+1],i+1);
		//printf("qwq\n");
		LL T=Read();
		while (T--){
			int n=Read(),m1=Read(),m2=Read();
			for(int i=1;i<=m1;++i) ar[i]=Read();
			for(int i=1;i<=m2;++i) br[i]=Read();
			if(ar[m1]!=br[1]||ar[1]!=1||br[m2]!=n){
				printf("0\n");continue;
			}
			int ans=C(n-1,ar[m1]-1);
			for(int i=1;i<m1;++i){
				ans=mul(ans,A(ar[i+1]-2,ar[i+1]-ar[i]-1));
			}
			for(int i=1;i<m2;++i){
				ans=mul(ans,A(n-br[i]-1,br[i+1]-br[i]-1));
			}
			printf("%d\n",ans);
		}
		return 0;
	}	

F.Nobody is needed

做法tag:树状数组,离线

题目翻译

给定一个长度为\(n\)的排列\(a\)。给询问次数\(q\),每一次询问给两个参数\(l,r\)。要求输出合法序列数。下面数合法序列条件。
序列长度记为\(k(k>=1)\),记序列为\((t_1,t_2,...t_k)\)
1.\(l<=t_1<t_2<...<t_k<=r\)
2.对于整数\(i \in [1,k-1],a_{t_i+1}\)是\(a_{t_i}\)的倍数。

解法

首先我们得知道怎么计算合法序列数。
举例的时候我用数字而非下标表示合法序列,一样的。
以样例为例。排列\(2\ 1\ 6\ 3\ 5\ 4\ 8\ 7\),对于询问\(l=1,r=8\),合法序列有很多,我们考虑\(8\)作为结尾的\((8),(4,8),(1,4,8),(2,4,8),(1,8),(2,8)\)
我们对这些做一个分类\((8)\times 1,(...,4,8)\times 3,(..,1,8)\times 1,(...,2,8)\times 1\)
而我们可以发现以\(4\)结尾的序列数为\((4),(1,4),(2,4)\)恰好是\(3\)个,而\((...,4,8)\)也是\(3\)个。
这显然是因为加入\(8\)做结尾对\(4\)毫无影响,所以\(4\)的序列数全部被\(8\)继承了。
所以,我们知道对于给定的序列,某一个数\(x\)位置记录为\(pos_x\),以\(x\)结尾的序列数记录为\(cnt_x\)。
\([Exp]=\begin{cases}1& if\ Exp=true \\ 0 & if\ Exp = false \end{cases}\)

\[cnt_x=1+\sum_{d|x} [r>=pos_x>pos_d>=l]\times cnt_d \]

位置前面的不会继承后面的,所以从前往后做即可。
这样子的话就是对于一个给定区间,我们通过记录每个数作为序列结尾的贡献得到合法序列数。但是区间变化的话就只能重新遍历一遍重做了。复杂度\(O(n^2\log n)\)

序列尾作贡献的话就只能固定序列尾,如果固定一个序列尾不能确定序列是否在所需要的区间里面,所以我们还得固定序列头。
假设序列尾是\(z\),那么序列头\(x\)形成的二元组\(<x,z>\)贡献为(必须满足\(x|z\)否则没有贡献)

\[cnt_{<x,z>}=\sum_{\large d|\dfrac zx}[pos_z>pos_{d\times x}]\times cnt_{d\times x} \]

特别的\(cnt_{<x,x>}=1\)

那么接下来,问题就变成了,给定一个区间,求所有被包含的二元组的贡献和。

正常在线一个一个做的复杂度合格做法我没有想到,所以我就先把所有询问离线下载,按照\(r\)升序,记序列头尾形成的二元组\(<x,z>\),满足\(z<=r\)的序列尾满足要求,有可能产生贡献,把贡献记录在序列头的位置上。因为\(r\)升序,所以只会添加记录而不会删除记录,然后对于每一次询问,\(l<=x<=r\)的序列头合法,把这部分贡献加起来。区间查询加单点修改,树状数组和线段树随便选一个即可。

复杂度分析

记录数也就是因子数之和,\(O(n\log n)\),再修改\(O(\log n)\),再加\(O(\log n)\)查询,\(n,q\)同级
时间复杂度\(O(n\log^2 n)\)
因为要记录每个数的因子,空间复杂度\(O(n\log n)\),序列贡献可以询问来了当场加进去,可以不存。

点我查看代码
#include<bits/stdc++.h> 
#define ll long long 
//#define int long long
#define mid ((l+r)>>1)
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
#define inf 0x3f3f3f3f 
typedef int LL;
const signed maxn=(signed)1e6+5;
inline LL Read(){
	char ch=getchar();bool f=0;LL x=0;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')f=1;
	for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
	if(f==1)x=-x;return x;
}
int n,q;
std::vector<int> d[maxn];
ll cnt[maxn];
int pos[maxn],ar[maxn];
struct Q{
	int l,r,id;
}qr[maxn];
ll ans[maxn];
bool operator <(Q a,Q b){
	if(a.r!=b.r) return a.r<b.r;
	return a.l<b.l;
}
ll tr[maxn];
void Modify(int x,ll w){
	while(x<=n){
		tr[x]+=w;
		x+=x&-x;
	}
} 
ll Query(int x){
	ll ans=0;
	while(x){
		ans+=tr[x];
		x-=x&-x;
	}
	return ans;
}
void solve(int posi){
	int x=ar[posi];
	cnt[x]=1;
	Modify(posi,1);
	for(auto j:d[x]){
		cnt[j]=(pos[j]<posi);
		for(auto z:d[x/j]){
			if(pos[z*j]>pos[j]) cnt[j]+=cnt[z*j];
		}
		//printf("r=%d,ar[r]=%d,l=%d,ar[l]=%d,c=%lld\n",posi,x,pos[j],j,cnt[j]);
		Modify(pos[j],cnt[j]);
	}
}
signed main()
	{	 
		int mx=1e6;
		for(int i=(mx>>1);i;--i)
			for(int j=2;i*j<=mx;++j) d[i*j].push_back(i);
		LL T=Read();
		while (T--){
			n=Read(),q=Read();
			for(int i=1;i<=n;++i) ar[i]=Read();
			for(int i=1;i<=n;++i) pos[ar[i]]=i;
			for(int i=1;i<=n;++i) tr[i]=0;
			for(int i=1;i<=q;++i){
				int l(Read()),r(Read());
				qr[i]=(Q){l,r,i};
			}
			std::sort(qr+1,qr+1+q);
			int cnt=0;
			for(int i=1;i<=q;++i){
				int l=qr[i].l,r=qr[i].r;
				while(cnt<r) solve(++cnt);
				ans[qr[i].id]=Query(r)-Query(l-1);
			}
			for(int i=1;i<=q;++i) printf("%lld ",ans[i]);putchar('\n');
		}
		return 0;
	}	

标签:最大数,int,题解,codeforces,long,pos,div,times,define
From: https://www.cnblogs.com/LOOP-0/p/18091807

相关文章

  • CF494C Helping People 题解
    题目传送门前置知识概率DP|树形DP|RMQ解法观察到区间只有相离或包含关系,类似线段树的管辖区间,考虑将其构成树形关系。为方便代码书写,将原来的森林构成一棵树,即增加一个区间\(l_{q+1}=1,r_{q+1}=n,p_{q+1}=0\)。由于对于一个区间\([l,r]\)的最大值在经历任意次操作后,......
  • CF922E Birds 题解
    题目传送门前置知识背包DP解法观察到\(w\)极大,若使用正常的背包空间会爆炸。依据AT_dp_eKnapsack2的经验,考虑将背包“反”着用。设\(f_{i,j}\)表示到第\(i\)棵树时一共召唤了\(j\)只小鸟时剩余的最大魔力值,状态转移方程为\(f_{i,j}=\min(\max\limits_{k=0}^{\m......
  • [暴力题解系列] 2023年蓝桥杯-冶炼金属
    世界上存在很难的题,但不存在暴力偷不到分的题​ 这题的暴力思路比你想的更简单,我直接枚举v的数值不就行了?#include<iostream>#include<algorithm>usingnamespacestd;inta[10010],b[10010];intmain(){intn;scanf("%d",&n);for(inti=1;i<=n;i++)......
  • P10268 符卡对决 题解
    题目链接:符卡对决视频讲解待上传经典的题目,对于这个\([l,r]\)询问,我们先关注期望怎么算。考虑方案总数和有效的和,方案总数显然有\(\dfrac{n\times(n-1)}{2}\),现在还需要关注有效和,我们关注对于若干个有效的关系用一个比较形象的数据结构表示-----并查集,那么两个卡牌之间有......
  • CF1711B Party 题解
    CF1711BParty原题题意给定$n$个点带点权的无向图,点权$a_i$保证无重边自环,点权非负),要求删去一些点和它相连的边,使得剩下这个图的边数为偶数且删去点的点权之和最小。问删去点的点权之和最小是多少?分类讨论我们分类讨论一下。$m$为偶数,则不需要删边或点,直接输出$0$即......
  • 洛谷P3498 [POI2010] KOR-Beads 题解
    P3498[POI2010]KOR-Beads对于数列${A_i}$,求$k$使数列被分为$\lfloor\frac{n}{k}\rfloor$个部分后不同子数列种类最多(子串翻转前后为一类子串)很容易想到:枚举$k\\in\[1,n]$,记录每个$k$下不同种类数,然后取最优即可,那么问题来了:如何计算种类数?暴戾算法:一种纯......
  • 跳马【华为OD机试JAVA&Python&C++&JS题解】
    一.题目马是象棋(包括中国象棋和国际象棋)中的棋子,走法是每步直一格再斜一格,即先横着或直着走一格,然后再斜着走一个对角线,可进可退,可越过河界,俗称“马走‘日’字。给顶m行n列的棋盘(网格图),棋盘上只有有棋子象棋中的棋子“马”,并且每个棋子有等级之分,等级为k的马可以跳1~k......
  • CF710D Two Arithmetic Progressions 题解
    CF710DTwoArithmeticProgressions根号分治薄纱数论看日报学习的根号分治:暴力美学——浅谈根号分治-paulzrm的博客。开始想学ODT的映射思想的推广-金珂拉的博客,结果先学了ODT,又学了根号分治,才搞懂前置知识。什么是根号分治根号分治,是暴力美学的集大成体现。与......
  • [暴力题解系列]2023年蓝桥杯-子串简写
    ​ 大伙都说暴力是最低级的算法,啊那确实。但是好的暴力才是真正牛逼的骗分。咱就是说,暴力如何骗分呢?就是基于最暴力的算法一步步优化到能得更多分的暴力。子串简写这题,首先第一步就能想到一件事情:暴力枚举子串开头和末尾的位置,检查是否是符合题目要求的字符,如果是,并且长度大于......
  • 题解:AT_arc174_a [ARC174A] A Multiply
    题传。先要将\(C\)分类。\(C>0\),为了使答案更大,要乘上一个最大的区间和。\(C\le0\),为了使答案更大,选择乘上一个最小的区间和,因为此时我们可以贪心地想,如果区间和越小,乘上一个负数或\(0\)后,答案减少得越小,甚至乘上负数,还会使答案增大,所以也可以用负负得正来解释。当......