题解 [UNR #6] 小火车

传送门

只会 \(O(3^{\frac{n}{2}})\)
数据随机那档 meeting in middle 的时候在两边多随点状态就行了
但是我看错时限卡时卡错了,寄

然后正解:
首先发现本题一定有解
证明考虑鸽巢原理,有 \(2^n>p\) 种可能,那么一定存在两个集合权值相等

  • 关于「权值相同的无交集合」:
    一个常见 trick 是无交的限制无意义。找到两个权值相同的集合,删去公共部分即可得到两个权值相同的无交集合

那么这个题就是要找两个权值相同的无交集合
那么可以二分找出一个对应了多个集合的权值 \(mid\),check 可以 meet in middle 后每次双指针
然后找到一个 \(mid\) 后找方案也是同样的方法
复杂度 \(O(2^{\frac{n}{2}}\log n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 10000010
#define fir first
#define sec second
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
	ll ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

ll n, p;
ll a[100];
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a,b>>=1) if (b&1) ans=ans*a; return ans;}

pair<ll, ll> sta1[N], sta2[N];
int tem[100], top1, top2, siz1, siz2;

namespace force{
	inline void decode1(ll s) {for (int i=1; i<=siz1; ++i) tem[i]=s%3, s/=3;}
	inline void decode2(ll s) {for (int i=1; i<=siz2; ++i) tem[i]=s%3, s/=3;}
	void solve() {
		siz1=n>>1, siz2=n-siz1;
		int lim1=qpow(3, siz1), lim2=qpow(3, siz2);
		for (int s=0; s<lim1; ++s) {
			decode1(s);
			ll val=0;
			for (int i=1; i<=siz1; ++i)
				if (tem[i]==1) val+=a[i];
				else if (tem[i]==2) val+=p-a[i];
			// assert(val>=0);
			sta1[++top1]={val%p, s};
		}
		for (int s=0; s<lim2; ++s) {
			decode2(s);
			ll val=0;
			for (int i=1; i<=siz2; ++i)
				if (tem[i]==1) val+=a[siz1+i];
				else if (tem[i]==2) val+=p-a[siz1+i];
			// assert(val>=0);
			sta2[++top2]={val%p, s};
		}
		sort(sta1+1, sta1+top1+1);
		sort(sta2+1, sta2+top2+1);
		// cout<<"sta1: "; for (int i=1; i<=top1; ++i) cout<<"("<<sta1[i].fir<<','<<sta1[i].sec<<") "; cout<<endl;
		int p1=1, p2=1;
		for (; p1<top1&&!sta1[p1+1].fir; ++p1);
		for (; p2<top2&&!sta2[p2+1].fir; ++p2);
		if (p1!=1||p2!=1) {
			decode1(sta1[p1].sec);
			for (int i=1; i<=siz1; ++i) printf("%d ", tem[i]?(tem[i]==1?1:-1):0);
			decode2(sta2[p2].sec);
			for (int i=1; i<=siz2; ++i) printf("%d ", tem[i]?(tem[i]==1?1:-1):0);
			printf("\n");
			exit(0);
		}
		for (int p1=1,p2=top2; p1<=top1; ++p1) {
			for (; p2>1&&sta1[p1].fir+sta2[p2].fir>p; --p2);
			if (sta1[p1].fir+sta2[p2].fir==p) {
				decode1(sta1[p1].sec);
				for (int i=1; i<=siz1; ++i) printf("%d ", tem[i]?(tem[i]==1?1:-1):0);
				decode2(sta2[p2].sec);
				for (int i=1; i<=siz2; ++i) printf("%d ", tem[i]?(tem[i]==1?1:-1):0);
				printf("\n");
				exit(0);
			}
		}
		puts("IMPOSSIBLE");
	}
}

namespace task1{
	random_device seed;
	mt19937_64 rand(seed());
	inline void decode1(ll s) {for (int i=1; i<=siz1; ++i) tem[i]=s%3, s/=3;}
	inline void decode2(ll s) {for (int i=1; i<=siz2; ++i) tem[i]=s%3, s/=3;}
	void solve() {
		siz1=n>>1, siz2=n-siz1;
		ll lim1=qpow(3, siz1), lim2=qpow(3, siz2);
		for (int i=1; i<=2000000; ++i) {
			ll s=rand()%lim1;
			decode1(s);
			ll val=0;
			for (int i=1; i<=siz1; ++i)
				if (tem[i]==1) val+=a[i];
				else if (tem[i]==2) val+=p-a[i];
			// assert(val>=0);
			sta1[++top1]={val%p, s};
		}
		for (int i=1; i<=2000000; ++i) {
			ll s=rand()%lim2;
			decode2(s);
			ll val=0;
			for (int i=1; i<=siz2; ++i)
				if (tem[i]==1) val+=a[siz1+i];
				else if (tem[i]==2) val+=p-a[siz1+i];
			// assert(val>=0);
			sta2[++top2]={val%p, s};
		}
		sort(sta1+1, sta1+top1+1);
		sort(sta2+1, sta2+top2+1);
		// cout<<"sta1: "; for (int i=1; i<=top1; ++i) cout<<"("<<sta1[i].fir<<','<<sta1[i].sec<<") "; cout<<endl;
		int p1=1, p2=1, pos1=0, pos2=0;
		for (; p1<top1&&!sta1[p1+1].fir; ++p1) if (sta1[p1].sec) pos1=p1;
		for (; p2<top2&&!sta2[p2+1].fir; ++p2) if (sta2[p2].sec) pos2=p2;
		if (pos1&&pos2) {
			p1=pos1, p2=pos2;
			decode1(sta1[p1].sec);
			for (int i=1; i<=siz1; ++i) printf("%d ", tem[i]?(tem[i]==1?1:-1):0);
			decode2(sta2[p2].sec);
			for (int i=1; i<=siz2; ++i) printf("%d ", tem[i]?(tem[i]==1?1:-1):0);
			printf("\n");
			exit(0);
		}
		for (int p1=1,p2=top2; p1<=top1; ++p1) {
			for (; p2>1&&sta1[p1].fir+sta2[p2].fir>p; --p2);
			if (sta1[p1].fir+sta2[p2].fir==p) {
				decode1(sta1[p1].sec);
				for (int i=1; i<=siz1; ++i) printf("%d ", tem[i]?(tem[i]==1?1:-1):0);
				decode2(sta2[p2].sec);
				for (int i=1; i<=siz2; ++i) printf("%d ", tem[i]?(tem[i]==1?1:-1):0);
				printf("\n");
				exit(0);
			}
		}
		puts("IMPOSSIBLE");
	}
}

namespace task{
	int top1, top2;
	pair<ll, ll> sta1[N], sta2[N];
	ll qcnt(ll l, ll r) {
		// cout<<"qcnt: "<<l<<' '<<r<<endl;
		ll ans=0;
		for (int i=1,p1=top2,p2=top2; i<=top1; ++i) {
			while (p1&&sta1[i].fir+sta2[p1].fir>=l) --p1;
			while (p2&&sta1[i].fir+sta2[p2].fir>r) --p2;
			ans+=p2-p1;
			// cout<<"p: "<<p1<<' '<<p2<<endl;
		}
		// cout<<"now: "<<ans<<endl;
		l+=p, r+=p;
		// cout<<"lr: "<<l<<' '<<r<<endl;
		for (int i=1,p1=top2,p2=top2; i<=top1; ++i) {
			while (p1&&sta1[i].fir+sta2[p1].fir>=l) --p1;
			while (p2&&sta1[i].fir+sta2[p2].fir>r) --p2;
			ans+=p2-p1;
			// cout<<"p: "<<p1<<' '<<p2<<endl;
		}
		// cout<<"return: "<<ans<<endl;
		return ans;
	}
	void print(ll s, ll t) {
		// ll val1=0, val2=0;
		// for (int i=0; i<n; ++i) if (s&(1ll<<i)) val1+=a[i+1];
		// for (int i=0; i<n; ++i) if (t&(1ll<<i)) val2+=a[i+1];
		// assert(val1%p==val2%p);
		ll mask=s&t;
		s^=mask; t^=mask;
		for (int i=0; i<n; ++i)
			if (s&(1ll<<i)) printf("1 ");
			else if (t&(1ll<<i)) printf("-1 ");
			else printf("0 ");
		printf("\n");
		exit(0);
	}
	void solve() {
		int siz1=n>>1, siz2=n-siz1;
		int lim1=1<<siz1, lim2=1<<siz2;
		for (int s=0; s<lim1; ++s) {
			ll val=0;
			for (int i=0; i<siz1; ++i) if (s&(1<<i))
				val+=a[1+i];
			sta1[++top1]={val%p, s};
		}
		for (int s=0; s<lim2; ++s) {
			ll val=0;
			for (int i=0; i<siz2; ++i) if (s&(1<<i))
				val+=a[1+siz1+i];
			sta2[++top2]={val%p, s};
		}
		sort(sta1+1, sta1+top1+1);
		sort(sta2+1, sta2+top2+1);
		// cout<<"sta1: "; for (int i=1; i<=top1; ++i) cout<<"("<<sta1[i].fir<<','<<sta1[i].sec<<") "; cout<<endl;
		// cout<<"sta2: "; for (int i=1; i<=top2; ++i) cout<<"("<<sta2[i].fir<<','<<sta2[i].sec<<") "; cout<<endl;
		ll l=0, r=p-1, mid;
		while (l<r) {
			// cout<<"lr: "<<l<<' '<<r<<' '<<qcnt(l, r)<<endl;
			mid=(l+r+1)>>1;
			// cout<<"val: "<<qcnt(mid, r)<<endl;
			if (qcnt(mid, r)>r-mid+1) l=mid;
			else r=mid-1;
		}
		mid=l;
		// cout<<"mid: "<<mid<<endl;
		// cout<<"cnt: "<<qcnt(510, 510)<<endl;
		bool any=0; ll s;
		for (int p1=1,p2=top2; p1<=top1; ++p1) {
			for (; p2>1&&sta1[p1].fir+sta2[p2].fir>mid; --p2);
			// if (sta1[p1].fir+sta2[p2].fir==mid) cout<<"1"<<endl;
			for (int i=p2; i&&sta1[p1].fir+sta2[i].fir==mid; --i)
				if (!any) any=1, s=(sta2[i].sec<<siz1)|sta1[p1].sec;
				else print(s, (sta2[i].sec<<siz1)|sta1[p1].sec);
		}
		mid+=p;
		for (int p1=1,p2=top2; p1<=top1; ++p1) {
			for (; p2>1&&sta1[p1].fir+sta2[p2].fir>mid; --p2);
			// if (sta1[p1].fir+sta2[p2].fir==mid) cout<<"1"<<endl;
			for (int i=p2; i&&sta1[p1].fir+sta2[i].fir==mid; --i)
				if (!any) any=1, s=(sta2[i].sec<<siz1)|sta1[p1].sec;
				else print(s, (sta2[i].sec<<siz1)|sta1[p1].sec);
		}
		int cnt=0;
		for (int i=1; i<=top1; ++i)
			for (int j=1; j<=top2; ++j)
				if (sta1[i].fir+sta2[i].sec==mid)
					++cnt;
		// cout<<"cnt: "<<cnt<<endl;
		// cout<<qcnt(0, p-1)<<endl;
		assert(0);
	}
}

signed main()
{
	n=read(); p=read();
	for (int i=1; i<=n; ++i) a[i]=read();
	// if (n<=20) force::solve();
	// else task1::solve();
	task::solve();

	return 0;
}
posted @ 2022-08-08 07:18  Administrator-09  阅读(3)  评论(0编辑  收藏  举报