题解 math

传送门

赛时用一个奇怪的方法过掉了
首先\(b_i\)的有效范围是\([0, k-1]\)
发现不同的\(a_i*b_i\)会有很多重的
考虑把\(a_i\%k\),然后由小到大排序
按顺序扫,如果某个\(a_i\)已经可以被某个\(a_j\%k\)的倍数表示出来,那这个\(a_i\)就无效化了
这个可以用埃氏筛实现
最后会剩下一些仍有效的\(a_i\),但由于一些性质(我不太懂)剩下的数会极少,一般只剩下一个
那就可以\(O(k^n)\)暴力处理了
这个性质很有趣,随机数据几乎卡不掉,跑了半个小时才跑出来一个剩10个数的

然后正解:
一个看着很显然但遇到题不容易想到的结论:

  • \(ax+by=z\) 有整数解的条件是 \(gcd(a, b)|z\)

所以 \((\sum a_i*b_i)\%k\) 就一定是 \(gcd(a_i, a_{i+1}, ...)\) 的倍数
那求个gcd,不断乘\(k\)就行了
所以我从哪能联想到这个结论啊

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000100
#define ll long long 
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long 

#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
	int 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, k;
ll a[N];
int q[N], top;
bool vis[N];

namespace force{
	int lst[N], top2, cnt;
	void dfs(int u, int sum) {
		if (u>top2) {vis[sum]=1; return ;}
		for (int i=0; i<k; ++i) dfs(u+1, (sum+1ll*lst[u]*i%k)%k);
	}
	void solve() {
		vis[0]=1;
		for (int i=1; i<=n; ++i) a[i]=read()%k;
		sort(a+1, a+n+1);
		for (int i=1; i<=n; ++i) {
			if (a[i] && !vis[a[i]]) {
				for (int j=1; j<k; ++j) vis[a[i]*j%k]=1;
				lst[++top2]=a[i];
			}
		}
		for (int i=0; i<k; ++i) if (vis[i]) ++cnt;
		//cout<<"top2: "<<top2<<endl;
		if (cnt==k) {
			for (int i=0; i<k; ++i) if (vis[i]) q[++top]=i;
			printf("%d\n", top);
			for (int i=1; i<=top; ++i) printf("%d ", q[i]);
			printf("\n");
			exit(0);
		}
		dfs(1, 0);
		for (int i=0; i<k; ++i) if (vis[i]) q[++top]=i;
		printf("%d\n", top);
		for (int i=1; i<=top; ++i) printf("%d ", q[i]);
		printf("\n");
		exit(0);
	}
}

namespace task1{
	void solve() {
		vis[0]=1;
		for (int i=1; i<=n; ++i) a[i]=read()%k;
		for (int i=1; i<=n; ++i) {
			if (a[i] && !vis[a[i]]) {
				for (int j=1; j<k; ++j) vis[a[i]*j%k]=1;
			}
		}
		for (int i=0; i<k; ++i) if (vis[i]) q[++top]=i;
		printf("%d\n", top);
		for (int i=1; i<=top; ++i) printf("%d ", q[i]);
		printf("\n");
		exit(0);
	}
}

namespace task{
	ll gcd(ll a, ll b) {return !b?a:gcd(b, a%b);}
	void solve() {
		for (int i=1; i<=n; ++i) a[i]=read();
		ll t=a[1];
		for (int i=2; i<=n; ++i) t=gcd(t, a[i]);
		for (int i=0; i<k; ++i) vis[t*i%k]=1;
		for (int i=0; i<k; ++i) if (vis[i]) q[++top]=i;
		printf("%d\n", top);
		for (int i=1; i<=top; ++i) printf("%d ", q[i]);
		printf("\n");
		exit(0);
	}
}

signed main()
{
	#ifdef DEBUG
	freopen("1.in", "r", stdin);
	#endif
	
	n=read(); k=read();
	task::solve();

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