【UNR #6】小火车

【UNR #6】小火车

by AmanoKumiko

Description

给出长为\(n\)的序列\(a\),模数\(p\)

构造一个长为\(n\)的序列\(b\)

满足:

\(b_i\)不全为\(0\)

\(b_i\in\set{-1,0,1}\)

\(\sum a_ib_i\equiv 0\ (mod\ p)\)

Input

第一行两个数\(n,p\)

第二行\(n\)个数读入\(a\)

Output

一行\(n\)个数输出\(b\)

Sample Input

3 7
1 2 3

Sample Output

1 1 -1

Data Constraint

\(1\le n\le 40,p<2^n\)

Solution

搜索大师选拔赛

由于\(p<2^n\),所以一定有解

证明:

对于一个子集和,我们要把它放进\(0\cdots p-1\)中的一个桶中

而子集一共有\(2^n\)个,桶有\(p<2^n\)

所以至少有一个桶放了两个子集

我们可以直接二分出这个桶

而计算一个桶区间的子集数可以先折半,然后排序,双指针(其实有五个。。。)扫一扫

剩下的问题也是类似的,同样可以折半

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define N 50
#define LL long long

int n,len,t0,t1;
LL p,a[N],s0[1<<21],s1[1<<21];

LL mod(LL x){return x>=p?x-p:x;}

LL qur(LL l,LL r){
	int ta=t1+1,tb=t1,tc=t1+1,td=t1;
	LL res=0;
	F(i,1,t0){
		while(s1[ta-1]>=l-s0[i]&&ta-1>=1)ta--;
		while(s1[tb]>r-s0[i]&&tb>=1)tb--;
		while(s1[tc-1]>=l-s0[i]+p&&tc-1>=1)tc--;
		while(s1[td]>r-s0[i]+p&&td>=1)td--;
//		[ta,tb] [tc,td]
		if(ta<=tb&&tc<=td&&tb&&td){
			if(ta>=tc&&tb<=td)res+=tb-ta+1;
			else if(tc>=ta&&td<=tb)res+=td-tc+1;
			else if(ta>=tc&&ta<=td)res+=tb-ta+1;
			else if(tc>=ta&&tc<=tb)res+=td-ta+1;
			else res+=tb-ta+1+td-tc+1;
		}else{
			if(tb&&ta<=tb)res+=tb-ta+1;
			if(td&&tc<=td)res+=td-tc+1;
		}
	}
	return res;
}

LL w;

unordered_map<LL,LL>t;

vector<LL>sol;

void dfs1(int x,LL s,LL sta){
	if(x>len){t[s]=sta;return;}
	dfs1(x+1,s,sta);
	dfs1(x+1,mod(s+a[x]),sta|(1ll<<x-1));
}

void dfs2(int x,LL s,LL sta){
	if(x>n){if(t.find(mod(w-s+p))!=t.end())sol.push_back(sta|t[mod(w-s+p)]);return;}
	dfs2(x+1,s,sta);
	dfs2(x+1,mod(s+a[x]),sta|(1ll<<x-1));
}

int main(){
	scanf("%d%lld",&n,&p);
	F(i,1,n)scanf("%lld",&a[i]);
	len=n/2;
	F(i,0,(1<<len)-1){
		LL sum=0;
		F(j,1,len)if((1ll<<j-1)&i)sum=mod(sum+a[j]);
		s0[++t0]=sum;
	}
	F(i,0,(1<<n-len)-1){
		LL sum=0;
		F(j,len+1,n)if((1ll<<j-len-1)&i)sum=mod(sum+a[j]);
		s1[++t1]=sum;
	}
	sort(s0+1,s0+t0+1);
	sort(s1+1,s1+t1+1);
	LL le=-1,ri=p,mid;
	while(le<ri-1){
		mid=le+ri>>1;
		if(qur(le+1,mid)>mid-le)ri=mid;
		else le=mid;
	}
	w=ri;
	dfs1(1,0,0);
	dfs2(len+1,0,0);
	LL Sa=-1,Sb=-1;
	for(auto d:sol){
		if(Sa==-1)Sa=d;
		else if(Sb==-1)Sb=d;
	}
	LL tmp=Sa^Sb;
	Sa&=tmp;Sb&=tmp;
	F(i,1,n){
		if((1ll<<i-1)&Sa)printf("1 ");
		else if((1ll<<i-1)&Sb)printf("-1 ");
		else printf("0 ");
	}
	return 0;
}
posted @ 2022-08-08 15:40  冰雾  阅读(54)  评论(0编辑  收藏  举报