【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;
}