Codeforces Round 948 (Div. 2)(B~D)(构造思维,数论,哈希)

题目地址

B

类似树状数组

C

有点巧,像构造的思维。

首先判断 \(n\) 是否为答案(取最特殊、最极限情况),否则 \(\max\) 一定是 \(lcm\),那么对于所有 \(a_i\)\(a_i\) 一定是 \(\max\) 的约数。因此最后的“最长数组”的 \(lcm\) 一定也是 \(\max\) 的约数。(缩小答案范围

于是我们可以类似二分答案的“check”,check 每一个可能的 \(lcm\) 能得到的最长数组,其中最长的即答案。

由于约数是log级别,时间复杂度 \(O(\sqrt{1e9} + n\log{1e9})\)

#include<bits/stdc++.h>
using namespace std;
inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
const int N = 2007;
const int INF = 1e9;
int n;
int a[N];
int check(int l) {
	int cnt = 0;
	vector<int> b;
	for(int i=1;i<=n;++i) {
		if(l%a[i] == 0) ++cnt, b.push_back(a[i]);
	}
	for(int i=1;i<=n;++i) {
		if(l==a[i]) cnt = 0;
	}
	if(!b.size()) return 0;
	long long m = b[0];
	for(auto x : b) {
		m = (long long)m*x / __gcd(m, (long long)x);
	}
	if(m != (long long)l) cnt = 0;
	return cnt;
}
void solve() {
	n = read();
	for(int i=1;i<=n;++i) a[i] = read();
	sort(a+1, a+1+n);
	int mx = a[n];
	for(int i=1;i<=n;++i) {
		if(mx%a[i]) {
			printf("%d\n",n); return ;
		}
	}
	vector<int> d;
	for(int i=1;i<=sqrt(mx);++i) {
		if(mx%i==0) {
			d.push_back(i);
			d.push_back(mx/i);
		}
	}
	int ans = 0;
	for(auto l : d) {
		ans = max(ans, check(l));
	}
	printf("%d\n",ans);
	
	for(int i=1;i<=n;++i) a[i] = 0;
}
int main()
{
	int T = read();
	while(T--) solve();
	return 0;
}
/*
1
4
3 8889 14815 44445

0
*/

D

评价为比 C 简单

注意到:1、对一行操作两次是没有意义的。2、把一列变为全 0 的操作方案是唯一的。3、由 <2> 推得把一列变为只有一个 1 的操作方案有 \(n\) 种且互不相同

于是我们可以用一个数组存某一个操作方案可以让多少列合法。具体的:开一个数组,对于每一种能让该列合法的的操作方案,在它所对应的数组的值上加一,最后这个数组中的数就是表示该操作方案可以让多少列合法。(正确性参见 <3> “互不相同”)

操作方案用哈希值表示(试过了,自然溢出加base=2会wa,正常的模数加base=131单模数和双模数都能A)

时间复杂度 \(O(nm)\)

#include<bits/stdc++.h>
#define mp(a,b) make_pair(a,b)
#define int long long
using namespace std;
inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
typedef pair<int,int> pii;
const int N = 3e5+7;
const int mod1 = 1e9+7;
const int mod2 = 1;
const int Base = 131;
int pw1[N],pw2[N];
int n,m;
string s[N];
map<pair<int,int>,int> cnt;
void Init() {
	pw1[0] = pw2[0] = 1;
	for(int i=1;i<N;++i) pw1[i] = (pw1[i-1]*Base) % mod1;
	for(int i=1;i<N;++i) pw2[i] = (pw2[i-1]*Base) % mod2;
}
void solve() {
	n = read(), m = read();
	vector<vector<int> > a(n, vector<int>(m, 0));
	vector<vector<pii> > c(n, vector<pii>(m, mp(0, 0)));
	for(int i=0;i<n;++i) cin >> s[i];
	for(int i=0;i<n;++i) {
		for(int j=0;j<m;++j) {
			a[i][j] = s[i][j] - '0';
		}
	}
	for(int j=0;j<m;++j) {
		int st1 = 0, st2 = 0;
		for(int i=0;i<n;++i) {
			st1 = (st1 + a[i][j]*pw1[i]) % mod1;
			st2 = (st2 + a[i][j]*pw2[i]) % mod2;
		}
		for(int i=0;i<n;++i) {
			int nst1 = st1, nst2 = st2;
			if(a[i][j] == 0) nst1 += pw1[i], nst2 += pw2[i];
			else nst1 -= pw1[i], nst2 -= pw2[i];
			nst1 = (nst1%mod1 + mod1) % mod1;
			nst2 = (nst2%mod2 + mod2) % mod2;
			++cnt[mp(nst1, nst2)];
			c[i][j] = mp(nst1, nst2);
		}
	}
	int ans = 0, jd = 0, id = 0;
	for(int i=0;i<n;++i) {
		for(int j=0;j<m;++j) {
			int x = c[i][j].first, y = c[i][j].second;
			if(cnt[mp(x,y)] > ans) {
				id = i, jd = j, ans = cnt[mp(x,y)];
			}
		}
	}
	vector<int> as(n);
	for(int i=0;i<n;++i) as[i] = a[i][jd];
	as[id] ^= 1ll;
	printf("%lld\n",ans);
	for(int i=0;i<n;++i) printf("%lld",as[i]);
	cout << endl;
	
	cnt.clear();
}
signed main()
{
	Init();
	int T = read();
	while(T--) solve();
	return 0;
}
/*
1
1 3
100
*/ 
posted @ 2024-06-28 21:44  基地AI  阅读(26)  评论(0编辑  收藏  举报