格雷的疑惑

Problem Description
ivankevin loves sequences.
A sequence Gn of 2^n elements Gi is called a N-BIT REFLECTED GRAY SEQUENCE if:
1.Each element gi,j(0<=j<n) of Gi is a string contains n integers of 0 or 1.
2.G1=g1,0,g1,1=0,1.
3.if j<2^(n-1), then gn,j=0g(n-1),j,else gn,j=1g(n-1),2^n-1-j.
Now let a function f on gi,j be f(gi,j)=sum of all integers in gi,j. Given n, gn,a, and b, ivankevin wants to know the sum and the maximum of all f(gn,k mod 2^n) where a<=k<=a+b.
for example, let n=3, a=2, and b=3, then G3 is:
0 0 0,
0 0 1,
0 1 1,
0 1 0,
1 1 0,
1 1 1,
1 0 1,
1 0 0.
So f(g3,2)=2, f(g3,3)=1, then sum is 3 and the maximum is 2.
Input
The first line is an integer T, the number of test cases.
In each case, there are two integers n and b in the first line, as described. It is granted that 1<=n,b<=10000. The second line contains n integers of 0 or 1, indicating gn,a.
Output
For each test, print the sum and maximum to the relative query in a line, seqarated by a space.
Sample Input
1
3 1
0 0 1
Sample Output

3 2

//此题用到了树状数组的查找和更新功能
#include<stdio.h>
#include<string.h>
#define Max 100010
int tree[Max];
int input[Max];
int n,b;
int lowbit(int x)
{
    return x & (-x);
}
void modify(int x,int add)//一维
{  
    while(x<=n)  
    {      
        tree[x]+=add;    
        x+=lowbit(x); 
    }
}
int get_sum(int x)//求1到x之间的和
{  
    int ret=0; 
    while(x!=0)  
    {       
        ret+=tree[x];   
        x-=lowbit(x);   
    }  
    return ret;
}
int find()
{
	if(get_sum(1)==1) return 1;//树状数组小标只能从1开始,所以没有get_sum(0)这一项
	int low=2,high=n,mid;
	while(low<=high)
	{
		mid=(low+high)/2;
		if(get_sum(mid-1)==0&&get_sum(mid)==1)
			return mid;
		else if(get_sum(mid-1)>0)
			high=mid-1;
		else low=mid+1;
	}
	return 0;//没找到的话,返回0
}
int main()
{
	//freopen("b.txt","r",stdin);
	int i,t,sum,max_sum,pos,total;
	scanf("%d",&t);
	while(t--)
	{
		memset(tree,0,sizeof(tree));
		scanf("%d %d",&n,&b);
		for(i=1;i<=n;i++)
			scanf("%d",&input[n-i+1]);
		for(i=1;i<=n;i++)
			modify(i,input[i]);
		total=sum=max_sum=get_sum(n);
		while(b--)
		{
			if(sum%2==0) pos=1;//偶数行变奇数行,把第一个元素改变
			else
			{
				pos=find();
				if(pos==n&&input[pos]==1) 
				{
					sum=0;
					input[pos]=0;
					modify(n,-1);
					continue;//跳过以下的操作
				}
				else pos+=1;//奇数行变偶数行,找到该序列中的第一个1,然后将其后数字改变
			}
			if(input[pos]==1)
			{
				sum--;
				modify(pos,-1);
				input[pos]=0;
			}
			else 
			{
				sum++;
				modify(pos,1);
				input[pos]=1;
			}
			total+=sum;
			if(sum>max_sum) max_sum=sum;
		}
		printf("%d %d\n",total,max_sum);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值