题面:https://www.cnblogs.com/Juve/articles/11556809.html

Set:

题干中说的M个数两两不同是说不能重复选同一个位置的数,而不是不能选数值相同的数,所以不用取重

题目中说是子集,其实连续的序列中就有答案

我们处理出mod N下的前缀和,如果有两个前缀和相同,那么选这两个前缀和中间的数即可,因为减完之后余数为0

这样一定能保证正确吗?或者一定存在两个前缀和相等的情况吗?

在mod N先前缀和最多有0~N-1这N种取值,但是一共有N+1个前缀和(sum[0]也算一种),所以一定有答案

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define MAXN 1000005
#define re register
using namespace std;
int n,sum[MAXN],a[MAXN],pos[MAXN];
inline int read(){
re int x=0;re char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
}
signed main(){
n=read();
for(re int i=1;i<=n;++i){
a[i]=read();
sum[i]=(sum[i-1]+a[i]%n)%n;
if(!pos[sum[i]]) pos[sum[i]]=i;
else{
re int j=pos[sum[i]];
printf("%d\n",i-j);
for(re int p=j+1;p<=i;++p){
printf("%d ",p);
}
puts("");
return 0;
}
}
return 0;
}

Read:

一个显然的结论,设数量最多的书出现的次数为k,那么答案就是max(0,2×k-n-1)

但是题目卡空间,不能存下,所以我们要想顺序访问每一个元素就让它从新生成一遍

先扫第一遍,记录一个cnt和id,如果cnt=0,那么cnt=1,id=a[i],

如果id=a[i],cnt++,如果不等,cnt--,那么最终留下的id就是出现次数最多的

然后再扫一遍统计id出现次数即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define re register
using namespace std;
const int MAXN=1005;
int n,m,k,cnt[MAXN],x[MAXN],y[MAXN],z[MAXN],S,id=0,sum=0,ans;
signed main(){
scanf("%d%d",&m,&k);
for(int i=1;i<=m;++i) scanf("%d",&cnt[i]);
for(int i=1;i<=m;++i) scanf("%d",&x[i]);
for(int i=1;i<=m;++i) scanf("%d",&y[i]);
for(int i=1;i<=m;++i) scanf("%d",&z[i]);
S=(1<<k)-1;
for(int i=1;i<=m;++i){
if(sum==0) id=x[i],sum=1;
else if(id==x[i]) ++sum;
else --sum;
long long last=x[i];
for(int j=1;j<cnt[i];++j){
last=(last*y[i]+z[i])&S;
if(sum==0) id=last,sum=1;
else if(id==last) ++sum;
else --sum;
}
}
sum=0;
for(int i=1;i<=m;++i){
n+=cnt[i];
if(x[i]==id) ++sum;
long long last=x[i];
for(int j=1;j<cnt[i];++j){
last=(last*y[i]+z[i])&S;
if(last==id) ++sum;
}
}
ans=max(0,sum*2-n-1);
printf("%d\n",ans);
return 0;
}

Race:

考虑怎么求出 x 的答案 . 平方相当于是枚举两个人 ( 可以相同 ), 把这两个人同时排在 x 前面的天数计入答案 . 那么对于 x, 如果我们求出 f[i] 也就是能力值的二进制中第 i+1 到 M-1 位都和他相等且第 i 位不同的人有多少个 , 那么这些人是否排在他前面只由第 i 位确定 , 一共有 2^(M-1) 天 , 而且不需要从这些人中枚举两个人了 , 因为直接平方即可 . 我们只要枚举 i 和 j, f[i] 这些人和 f[j] 这些人同时排在他前面的天数为2^(M-2), 所以把 2*f[i]*f[j]*2^(M-2) 计入答案 . 具体实现有很多方法 , 可以用 trie 树实现 ,记录trie上每一个节点被访问过的次数,在扫每一个a[i]时,它的f数组就是在当前二进制位上与他这一位相反的数被经过的次数,对于tr[root][p]和tr[root][p^1],因为要xor从0到2M-1,所以当前位xor出与他相反的次数是tr[root][p],和它相同的是tr[root][p^1].

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define int long long
#define re register
using namespace std;
const int MAXN=6000005;
const int mod=1e9+7;
int n,m,tot=1,ans=0,a[MAXN],f[MAXN];
int tr[MAXN][2],s[MAXN*2];
void insert(int val){
int root=1;
for(int i=m-1;i>=0;--i){
int p=(val>>i)&1;
if(!tr[root][p]) tr[root][p]=++tot;
++s[tr[root][p]];
root=tr[root][p];
}
}
int query(int val){
int res=0,root=1;
for(int i=m-1;i>=0;--i){
int p=(val>>i)&1;
f[i]=s[tr[root][p^1]];
for(int j=i;j<m;++j) (res+=(f[i]*f[j])%mod)%=mod;
root=tr[root][p];
}
return (res<<(m-1))%mod;
}
signed main(){
scanf("%lld%lld",&n,&m);
for(re int i=1;i<=n;++i){
scanf("%lld",&a[i]);
insert(a[i]);
}
for(int i=1;i<=n;++i){
ans^=query(a[i]);
}
printf("%lld\n",ans);
return 0;
}

最新文章

  1. 数据库设计中的Soft Delete模式
  2. 2016第16本:TED演讲的秘密
  3. Java程序员岗位
  4. Bootstrap学习笔记
  5. JavaSE基础01
  6. js判断字符串中是否含有指定汉语
  7. EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~终结~配置的优化和事务里读写的统一
  8. lr_save_var字符串截取总结
  9. [Python] 使用有道翻译API
  10. visual studio 插件开发
  11. 在eclipse如何删除无效的maven build
  12. iOS开发——实用技术OC篇&amp;事件处理详解
  13. CentOS_5.6下使用cmake编译MySQL_5.5.11教程
  14. .net MVC +EF+VUE做回合制游戏(二)
  15. Colorful Bricks CodeForces - 1081C ( 组合数学 或 DP )
  16. yum设置本地源
  17. HTML5 图片下载
  18. kerberos介绍
  19. centos清华源地址,ubuntu阿里云源
  20. 黑电-逻辑地址-0X4EB9FDE3- %o %d %x

热门文章

  1. JQUERY(入口函数 选择器)
  2. redis服务后台运行
  3. 转: sizeof,总结
  4. Git远程仓库版本回退
  5. nodejs之连接mysql数据库
  6. 关于tomcat配置了虚拟路径,但是在Idea中无法生效的问题
  7. 面试系列10 es生产集群的部署架构
  8. java_缓冲流(字节输出流)
  9. MFC注册热键
  10. LVS/Nginx/HAProxy负载均衡器的对比分析