2019南昌邀请赛重现F (找规律(异或)+线段树)

https://nanti.jisuanke.com/t/40258

题意:就是个这

F(l,r)=f(l,l)^f(l+1,r).......^f(r,r)

          ^f(l+1,r)^f(l+2,r)....^f(r,r)

          .......^f(r,r);

然后告诉了a[1-n],   f(l,r)=a[l]^.....^a[r];

两个操作:1.求F(l,r)    2. 把第i位改为j

输入T行,n, m, n为a大小,m为操作数

题解:啥都不要想(我也不知道为啥)直接打表找规律

可以发现当区间长度为偶数时,最后结果为0,为奇数时,最后结果F(l,r)=a[l]^a[l+2]^....直到l+2<=r;


int a[maxn];
int num[500][500];
int sum[500];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	int tmp;
	for(int i=1;i<=n;i++){
		for(int j=i;j<=n;j++){ tmp=a[i];
		    for(int k=i+1;k<=j;k++) tmp=tmp^a[k];num[i][j]=tmp;}}  
	int ans=0;
	for(int k=1;k<=n;k++){ ans=0;
	for(int i=1;i<=k;i++){
		for(int j=i;j<=k;j++){
			ans^=num[i][j];
		//	cout<<num[i][j]<<" ";}
	//	cout<<endl; }
	cout<<1<<"-"<<k<<" :"<<ans<<endl;}
	return 0;
} 
10
1 2 3 4 5 6 7 8 9 10

1-1 :1
1-2 :0
1-3 :2
1-4 :0
1-5 :7
1-6 :0
1-7 :0
1-8 :0
1-9 :9
1-10 :0

然后就线段树:因为区间长度为奇数时要从左端点开始隔一个取,所以搞两颗树

一颗只存下标偶数的值(奇数为0),只算偶数的异或;

另一颗同理;这样就可以简便的算区间长度为奇数的F(x,y)  比如F(1,3) 或F(2,5)

#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e5+7;
int ans[maxn*4];
int tmp[maxn*4];
int a[maxn];
void pushup(int p){
	ans[p]=ans[p<<1]^ans[p<<1|1];//奇数 
	tmp[p]=tmp[p<<1]^tmp[p<<1|1];//偶数 
}
void build(int l,int r,int p){
	if(l==r){
		if(l%2==1)
		ans[p]=a[l]; //奇数 
		else
		tmp[p]=a[l]; //偶数 
		return ;
	}
	int m=(l+r)>>1;
	build(l,m,p<<1);
	build(m+1,r,p<<1|1);
	pushup(p);
}
int query(int l,int r,int L,int R,int p){
	if(L<=l&&r<=R){
		if(L%2==1)//奇数 
		return ans[p];
		else return tmp[p]; //偶数 
	}
	int m=(l+r)>>1;
	int kk=0;
	if(L<=m)
	   kk=kk^query(l,m,L,R,p<<1);
	if(R>m)
	   kk=kk^query(m+1,r,L,R,p<<1|1);
	return kk;      
}
void update(int l,int r,int i,int j,int p){
	if(l==r){
		if(i%2==1)//奇数 
		ans[p]=j;
		else tmp[p]=j;//偶数 
		return ;
	}
	int m=(l+r)>>1;
	if(i<=m)
		update(l,m,i,j,p<<1);
	else
	    update(m+1,r,i,j,p<<1|1);	
    pushup(p);	
}
int main(){
	int t;
    scanf("%d",&t);
    int kase=1;
	while(t--){
		int n,m;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
		build(1,n,1);
		printf("Case #%d:\n",kase++);
		while(m--){
			int x,l,r;
			scanf("%d%d%d",&x,&l,&r);
			if(x==1){
				int ans=0;
				if((r-l+1)%2==1){
				  ans=query(1,n,l,r,1);
				  printf("%d\n",ans);
				}else
			         printf("0\n");
			}else{
				update(1,n,l,r,1);
			}
		}
	}
	return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值