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
*/