您的位置:首页 > 房产 > 家装 > 站长统计是什么意思_宁波网站建设制作推广_seo在线培训机构排名_杭州seo工作室

站长统计是什么意思_宁波网站建设制作推广_seo在线培训机构排名_杭州seo工作室

2024/10/6 6:03:28 来源:https://blog.csdn.net/m0_53714683/article/details/142211164  浏览:    关键词:站长统计是什么意思_宁波网站建设制作推广_seo在线培训机构排名_杭州seo工作室
站长统计是什么意思_宁波网站建设制作推广_seo在线培训机构排名_杭州seo工作室

题目大意

你需要构造一个长度为 n n n 的回文序列 a 1 , ⋯ , a n a_1,\cdots,a_n a1,,an,在这个序列的所有子串中,除了一个子串的和你不知道,其他所有 a a a 的子串的元素和你都知道,换句话说,你分别知道所有子串中 n ( n + 1 ) 2 − 1 \dfrac{n(n+1)}{2}-1 2n(n+1)1 个子串的和。请构造任意一个符合要求的序列。

“子串”的定义是整个序列中某个连续的一段。

t ≤ 200 t≤200 t200 n ≤ 1000 n≤1000 n1000 s i ≤ 1 0 9 s_i≤10^9 si109

题解

有趣的题,然而我是看了题解才会的。

首先考虑如果知道了全部子串的和应该怎么做。

发现原序列是回文的,就说明除了位于中间(l=n-r+1)的区间和外,每个区间和都会出现偶数次(左右对称),而位于中间的区间的区间和只会出现奇数次。于是我们就可以找出所有中间的区间,将他们排序后作差便可以得到整个序列。

可是对于这道题,如果缺失的子串和是这 n 2 \dfrac{n}{2} 2n 个中的某个时就用不了这个方法了。

然后我就不会了,以下部分是看了题解后才会的,用自己的理解讲一讲。

对于知道全部子串的和的问题,其实还有一种解法。

首先, n ( n + 1 ) 2 \dfrac{n(n+1)}{2} 2n(n+1) 个子串中最大值显然是 l = 1 , r = n l=1,r=n l=1,r=n 的子串的和,也就是整个序列的和,次大值显然是 l = 1 , r = n − 1 l=1,r=n-1 l=1,r=n1 l = 2 , r = n l=2,r=n l=2,r=n 的子串和,于是我们就可以推出 a 1 , a n a_1,a_n a1,an。第三大的值有可能是 l = 1 , r = n − 2 l=1,r=n-2 l=1,r=n2 (对称的就不赘述了)或 l = 2 , r = n − 1 l=2,r=n-1 l=2,r=n1,但是此时因为我们知道了 a 1 , a n a_1,a_n a1,an 的值,所以也可以推出 l = 2 , r = n − 1 l=2,r=n-1 l=2,r=n1 的值,把这个值删除后第三大的一定是 l = 1 , r = n − 2 l=1,r=n-2 l=1,r=n2,于是我们又可以推出 a 2 , a n − 1 a_2,a_{n-1} a2,an1 的值。第四大的值有可能是 l = 1 , r = n − 3 l=1,r=n-3 l=1,r=n3 l = 2 , r = n − 2 l=2,r=n-2 l=2,r=n2,我们可以推出 l = 2 , r = n − 2 l=2,r=n-2 l=2,r=n2 的值,把这个值删去后第四大的一定是 l = 1 , r = n − 3 l=1,r=n-3 l=1,r=n3 ,我们又可以推出 a 3 , a n − 2 a_3,a_{n-2} a3,an2 的值……以此类推,我们可以得到整个序列。

考虑下这个做法在什么情况下能使用。

如果缺失的子串是方法1中的位于中间的区间,即只出现奇数次,那么是会出问题的,反之其他的串都出现了偶数次,这个方法只需要找最大值,所以缺失一个不会有什么影响。在观察一下,发现大多数的区间最后都是要被删除的,真正需要用到的区间其实只有 1 , n 1,n 1,n 1 , n − 1 1,n-1 1,n1 1 , n − 2 1,n-2 1,n2 ……而这些区间中,只有 1 , n 1,n 1,n 是位于中间的。

也就是说,只要缺失的子串不是 1 , n 1,n 1,n ,就可以用方法2得出答案。而如果是 1 , n 1,n 1,n,在解法1中, 1 , n 1,n 1,n 的用处是和 2 , n − 1 2,n-1 2,n1 作差得到 a 1 , a n a_1,a_n a1,an,但其实这也可以通过 1 , n − 1 1,n-1 1,n1 2 , n − 1 2,n-1 2,n1 作差得到。 1 , n − 1 1,n-1 1,n1 是此时的最大值(因为本来的最大值缺失了,次大值就成了最大值), 2 , n − 1 2,n-1 2,n1 是所有出现过奇数次的数中的最大值,于是我们可以很快找到这两个数,求出 a 1 , a n a_1,a_n a1,an 后使用方法1就做完了。

复杂度 O ( m l o g m ) O(mlogm) O(mlogm) m = n ( n + 1 ) 2 − 1 m=\dfrac{n(n+1)}{2}-1 m=2n(n+1)1),瓶颈在排序。

代码

调了挺久的……感觉写起来有点鬼畜,当然也可能是因为我太笨了。

#include<bits/stdc++.h>
using namespace std;const int N=1000+5;int kase,n,m,cnt,a[N],b[N*N],c[N];
map<int,int> mp;bool cmp(int x,int y){return x>y;
}void init(){memset(a,0,sizeof(a));memset(c,0,sizeof(c));mp.clear();cnt=0;
}int main(){scanf("%d",&kase);while(kase--){init();scanf("%d",&n);m=n*(n+1)/2-1;for(int i=1;i<=m;i++)scanf("%d",&b[i]);sort(b+1,b+1+m,cmp);if(b[1]!=b[2]){int sum=b[1];for(int i=1;i<=m;i++){if(mp[b[i]]){mp[b[i]]--;continue;}c[++cnt]=b[i];mp[b[i]]++;if(cnt>1){a[cnt-1]=a[n-cnt+2]=c[cnt-1]-c[cnt];if(cnt*2>=n) break;mp[a[cnt-1]]+=2;sum-=2*a[cnt-1];int now=sum;mp[now]++;for(int i=cnt-1;i>1;i--){now+=a[i];mp[now]+=2;}}}if(n&1) a[n/2+1]=c[cnt]-(c[1]-c[cnt]);else a[n/2]=(c[cnt]-(c[1]-c[cnt]))/2;}else{int now=0;for(int i=1;i<=m;i++){now++;if(b[i]!=b[i+1]){if(now&1) c[++cnt]=b[i];now=0;}}a[cnt+1]=(n&1)?c[cnt]:c[cnt]/2;for(int i=cnt;i>=2;i--)a[i]=(c[i-1]-c[i])/2;a[1]=b[1]-c[1];}for(int i=1;i*2<=n;i++)printf("%d ",a[i]);if(n&1) printf("%d ",a[n/2+1]);for(int i=n/2;i>=1;i--)printf("%d ",a[i]);printf("\n");}return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com