AGC025F Addition and Andition

AGC025F

有两个长度为 n n n m m m的二进制数 x x x y y y。要做如下操作 k k k次:

x + = x & y , y + = x & y x+=x \& y,y+=x\&y x+=x&y,y+=x&y

k k k次之后 x x x y y y分别是多少。

n , m , k ≤ 1 0 6 n,m,k\le 10^6 n,m,k106


补很久前的题解。

模拟一下暴力:操作 k k k次,每次操作就是,从高位往低位,如果两个串对应位上的数为 ( 1 , 1 ) (1,1) (1,1),那么将这两位清空并且向前进一位。

不妨改变一下枚举的顺序:从高位往低位,如果两个串对应为上数为 ( 1 , 1 ) (1,1) (1,1),做 k k k次“向前移动”的操作(即当前位清空,如果前面为 ( 0 , 0 ) (0,0) (0,0),那么前面变成 ( 1 , 1 ) (1,1) (1,1),指针前移一位;如果前面为 ( 0 , 1 ) (0,1) (0,1),前面 x x x对应位变成 1 1 1 y y y对应位进位,若是存在形如 ( 100 , 011 ) (100,011) (100,011)变成 ( 101 , 100 ) (101,100) (101,100)的情况,那么指针移到前面那个 ( 1 , 1 ) (1,1) (1,1);前面不可能为 ( 1 , 1 ) (1,1) (1,1))。

用链表来维护状态相同的连续段。模拟即可。

势能分析,时间复杂度是对的:当前面有连续的 ( 0 , 0 ) (0,0) (0,0)时, O ( 1 ) O(1) O(1)移动过去,不影响;然后遇到连续的 ( 0 , 1 ) (0,1) (0,1)。当前面有连续的 ( 0 , 1 ) (0,1) (0,1)时,可能越过这连续的 ( 0 , 1 ) (0,1) (0,1)并且在前面创造了新的 ( 1 , 1 ) (1,1) (1,1)(创造新的 ( 1 , 1 ) (1,1) (1,1):连续的 ( 0 , 1 ) (0,1) (0,1)前有个 ( 1 , 0 ) (1,0) (1,0)),但是同时意味着这一段连续的 ( 0 , 1 ) (0,1) (0,1)变成 ( 0 , 0 ) (0,0) (0,0)(最后一个除外,变成 ( 1 , 0 ) (1,0) (1,0))。如果我们把 ( 0 , 1 ) (0,1) (0,1)连着 ( 1 , 0 ) (1,0) (1,0)的位置个数定义为势能,那么时间复杂度就显然了。


using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1000010
int n,m,k;
char str[N];
int s[N],t[N];
struct Node{
	Node *pre,*suc;
	int s,n;
} *fir,*lst;
Node *ins(Node *p,int s,int n=1){
	Node *nw=new Node;
	*nw={p,p->suc,s,n};
	if (p->suc)
		p->suc->pre=nw;
	else
		lst=nw;
	p->suc=nw;
	return nw;
}
Node *check(Node *p){
	if (p->n==0 || p->pre && p->s==p->pre->s){
		p->pre->n+=p->n;
		p->pre->suc=p->suc;
		if (p->suc)
			p->suc->pre=p->pre;
		else
			lst=p->pre;
		return p->pre;
	}
	return p;
}
int ans[N*2],cnt;
void print(int w){
	bool bz=0;
	for (int i=cnt-1;i>=0;--i){
		bz|=ans[i]>>w&1;
		if (bz)
			putchar('0'+(ans[i]>>w&1));
	}
	if (bz==0)
		putchar('0');
	putchar('\n');
}
int main(){
	scanf("%d%d%d",&n,&m,&k);
	scanf("%s",str);
	for (int i=0;i<n;++i)
		s[i]=str[n-1-i]-'0';
	scanf("%s",str);
	for (int i=0;i<m;++i)
		t[i]=str[m-1-i]-'0';
	n=max(n,m);	
	fir=lst=new Node;
	*lst=(Node){NULL,NULL,0,1000000000};
	for (int i=n-1;i>=0;--i)
		if (s[i]==1 && t[i]==1){
			int z=k;
			Node *p=lst;
			while (z){
				while (1){
					Node *q=check(p);
					if (q==p) break;
					p=q;
				}
				if (p->s==0){
					if (p->n<=z){
						z-=p->n;
						p=p->pre;
						if (z==0)
							ins(p,3,1);
					}
					else{
						p->n-=z;
						Node *q=ins(p,0,z);
						ins(p,3,1);
						break;
					}
				}
				else{
					while (1){
						Node *q=check(p->pre);
						if (q==p->pre) break;
						p->pre=q;
					}
					int m=p->s;
					if (p->pre->s==0){
						p->s=0,p->n--;
						Node *q=ins(p,m^3,1),*r=ins(q,0,1);
						p->pre->n--;
						check(p->pre);
						ins(p->pre,m,1);
						check(p);
						break;
					}
					else{
						p->s=0,p->n--;
						Node *q=ins(p,m^3,1),*r=ins(q,0,1);
						p->pre->n--;
						p=p->pre;
						z--;
						check(p->suc);
						if (z==0)
							ins(p,3,1);
						p=check(p);
					}
				}
			}
		}
		else
			lst=ins(lst,s[i]|t[i]<<1,1);
	for (Node *p=lst;p!=fir;p=p->pre)
		for (int i=0;i<p->n;++i)
			ans[cnt++]=p->s;
	print(0),print(1);
	return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看rEADME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看rEADME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值