Codeforces Round 1016 (Div. 3)(A~G)
比赛链接:https://codeforces.com/contest/2093
首次赛时龟速Akdiv3,这次头有点晕,写得很慢,很多题写得不够简约,考虑过个几天优化下吧。不要嫌弃我菜,哈哈。
E和G,Tle了.这次nlognlogn时间复杂度容易被卡,直接更新了题解。
A. Ideal Generator
思路:一上来完全没搞懂题目意思。看懂了后,就是偶数输出NO,奇数输出YES.因为偶数长度的回文数组造不出奇数
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll long long
// #define lowbit(x) (x & -x)
//#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>;find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
ll lcm(ll x, ll y)
{
x /= gcd(x, y);
return y * x;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
struct ss
{
ll l,r;
friend bool operator<(const ss& a, const ss& b)
{
return a.l< b.l;
};
};
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为上下左右,后面四个为角落
const ll N = 50005;
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
ll n;
cin>>n;
if(n&1)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
//3 132
//6 132465
//
B. Expensive Number
思路:最小成本肯定是删除到有且仅有一个数位且大于0得数。那么我们直接保留最后一个大于0的数位,删除前面大于0的数位(因为允许前导0,这样子做最佳)+后面0的个数。
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll long long
// #define lowbit(x) (x & -x)
//#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>;find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
ll lcm(ll x, ll y)
{
x /= gcd(x, y);
return y * x;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
struct ss
{
ll l,r;
friend bool operator<(const ss& a, const ss& b)
{
return a.l< b.l;
};
};
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为上下左右,后面四个为角落
const ll N = 50005;
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
string f;
cin>>f;
ll ans=0;
ll pd=0;
for(ll i=0;i<f.size();i++)
{
if(f[i]>='1')ans++,pd=i;
}
for(ll i=pd;i<f.size();i++)
{
ans+=(f[i]=='0');
}
ans--;
ans=max(ans,(ll)0);
cout<<ans<<endl;
}
}
//3 132
//6 132465
//
C. Simple Repetition
思路:看这道题时晕了,忘记了例如1313,其实能被13整除,卡了挺久。一开始还以为是个暴力。首先合数不管怎么样都不能变成质数。其次特判1,当k=1,其不是合数也不是质数,当k=2,其刚好为11,正好为质数,其他一定是合数。当k>=2,原本是质数的数将不能构造出质数,因为原质数就是因子之一。综上答案得出
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll long long
// #define lowbit(x) (x & -x)
//#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>;find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
ll lcm(ll x, ll y)
{
x /= gcd(x, y);
return y * x;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
struct ss
{
ll l,r;
friend bool operator<(const ss& a, const ss& b)
{
return a.l< b.l;
};
};
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为上下左右,后面四个为角落
const ll N = 50005;
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
ll n,k;
cin>>n>>k;
if(n==1)
{
if(k==1)cout<<"NO"<<endl;
else if(k==2)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
continue;
}
ll pd=0;
for(ll i=2;i*i<=n;i++)
{
if(n%i==0)
{
pd=1;
break;
}
}
if(pd)cout<<"NO"<<endl;//如果是合数
else if(k==1)cout<<"YES"<<endl;//质数就是质数
else cout<<"NO"<<endl;
}
}
//3 132
//6 132465
//
D. Skibidi Table
思路:推荐不要看我的。有点头晕,直接暴力写了。每次递归我会去问对应的行和列的区间,然后根据题目要求在进行划分区间。写过线段树的人肯定非常熟悉区间划分,这里不细讲了。
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll long long
// #define lowbit(x) (x & -x)
//#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>;find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
ll lcm(ll x, ll y)
{
x /= gcd(x, y);
return y * x;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
struct ss
{
ll l, r;
friend bool operator<(const ss& a, const ss& b)
{
return a.l < b.l;
};
};
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为上下左右,后面四个为角落
const ll N = 50005;
int main()
{
fio();
ll t;
cin >> t;
while (t--)
{
ll n, q;
cin >> n >> q;
function<ll(ll, ll, ll, ll, ll, ll, ll, ll)>dfs = [&](ll x, ll y, ll l, ll r, ll la, ll lb, ll ra, ll rb)
{
if (l == r)return l;
ll m1 = (la + lb) >> 1;
ll m2 = (rb + ra) >> 1;
ll len = (r - l + 1) / 4;
if (x <= m1)
{
if (y <= m2)
{
return dfs(x, y, l, l + len - 1, la, m1, ra, m2);
}
else
{
return dfs(x, y, l + len * 3, r, la, m1, m2 + 1, rb);
}
}
else
{
if (y <= m2)
{
return dfs(x, y, l + 2 * len, l + 3 * len - 1, m1 + 1, lb, ra, m2);
}
else
{
return dfs(x, y, l + len, l + len * 2 - 1, m1 + 1, lb, m2 + 1, rb);
}
}
};
function<pair<ll, ll>(ll, ll, ll, ll, ll, ll, ll)>fs = [&](ll d, ll l, ll r, ll la, ll lb, ll ra, ll rb)
{
//pair<ll,,ll>
if (l == r)
{
pair<ll, ll>j = { la,ra };
return j;
}
ll len = (r - l + 1) / 4;
ll m1 = (la + lb) >> 1;
ll m2 = (rb + ra) >> 1;
if (d <= l + len - 1)
{
return fs(d, l, l + len - 1, la, m1, ra, m2);
}
else if (d <= l + 2 * len - 1)
{
return fs(d, l + len, l + 2 * len - 1, m1 + 1, lb, m2 + 1, rb);
}
else if (d <= l + 3 * len - 1)
{
return fs(d, l + 2 * len, l + 3 * len - 1, m1 + 1, lb, ra, m2);
}
else return fs(d, l + 3 * len, l + 4 * len - 1, la, m1, m2 + 1, rb);
};
while (q--)
{
string f;
cin >> f;
if (f == "->")
{
ll x, y;
cin >> x >> y;
cout << dfs(x, y, 1ll, 1ll << (2 * n), 1ll, (1ll << n), 1ll, (1ll << n)) << endl;
}
else
{
ll d;
cin >> d;
pair<ll, ll>j = fs(d, 1ll, 1ll << (2 * n), 1ll, (1ll << n), 1ll, (1ll << n));
cout << j.first << " " << j.second << endl;
}
}
}
}
//3 132
//6 132465
//
E. Min Max MEX
思路:一开始看成子序列,心理一想,如此简单?随后样例没过,又瞄了一眼,子数组!但是也不难就是了。显然答案是具有单调性的,那么我去二分下这个这个最小mex(x),在遍历过程中,为了图个方便直接用set进行查询了,这样写时间复杂度是n * logn* logn了。每次去二分下能不能形成当前mex值u,如果有u就++,否则就break。由于添加的数字是乱的,所以得写个while循环,最后判断下,是否u大于等于二分的mex值,如果满足设为0,且分组++,最后看分组有没有大于等于k,即可判断二分往哪个方向压了。
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll long long
// #define lowbit(x) (x & -x)
//#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>;find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
ll lcm(ll x, ll y)
{
x /= gcd(x, y);
return y * x;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
struct ss
{
ll l, r;
friend bool operator<(const ss& a, const ss& b)
{
return a.l < b.l;
};
};
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为上下左右,后面四个为角落
const ll N = 50005;
int main()
{
fio();
ll t;
cin >> t;
while (t--)
{
ll n, k;
cin >> n >> k;
vector<ll>a(n + 5);
ll cnt = 0;
for (ll i = 1; i <= n; i++)
{
cin >> a[i];
cnt += (a[i] == 0);
}
if (cnt < k)cout << 0 << endl;
else
{
function<ll(ll)>ck = [&](ll x)
{
ll cnt = 0;
set<ll>d;
ll u = 0;
for (ll i = 1; i <= n; i++)
{
if (d.size() == 0)
{
d.insert(a[i]);
while (1)
{
auto j = d.lower_bound(u);
if (j == d.end())break;
if (*j == u)u++;
else break;
}
if (u >= x)cnt++, d.clear(),u=0;
}
else
{
d.insert(a[i]);
while (1)
{
auto j = d.lower_bound(u);
if (j == d.end())break;
if (*j == u)u++;
else break;
}
if (u >= x)cnt++, d.clear(), u = 0;
}
}
if (cnt >= k)return 1;
else return 0;
};
ll l = 1, r = n;
while (l <= r)
{
ll mid = (l + r) >> 1;
if (ck(mid))l = mid + 1;
else r = mid - 1;
}
cout << r << endl;
}
}
}
//3 132
//6 132465
//
上面代码TLE了。
这里给出更新后的代码:
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll long long
// #define lowbit(x) (x & -x)
//#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>;find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
/*
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}*/
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
ll lcm(ll x, ll y)
{
x /= gcd(x, y);
return y * x;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
struct ss
{
ll v, id;
friend bool operator<(const ss& a, const ss& b)
{
return a.v < b.v;
};
};
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为上下左右,后面四个为角落
ll n, m;
vector<ll> mul(vector<ll>& a, vector<ll>& b)
{
vector<ll>dp(m + 5);
for (ll i = 0; i <= m - 1; i++)
{
for (ll j = 0; j <= m - 1; j++)
{
dp[(i + j) % m] = (dp[(i + j) % m] + (a[i] * b[j]) % mod) % mod;
}
}
return dp;
}
vector<ll>ksm(vector<ll>& a, ll k)
{
vector<ll>tmp(m + 5, 0);
tmp[0] = 1;
while (k > 0)
{
if (k & 1)
{
tmp = mul(tmp, a);
}
a = mul(a, a);
k >>= 1;
}
return tmp;
}
bool vis[250000];
int main()
{
fio();
ll t;
cin >> t;
while (t--)
{
ll n, m;
cin >> n >> m;
vector<ll>a(n + 5);
ll cnt = 0;
ll f = 0;
for (ll i = 1; i <= n; i++)
{
ll x;
cin >> x;
f += (x == 0);
if (x >= 200001)continue;
else a[++cnt] = x;
}
if (f < m)
{
cout << 0 << endl;
continue;
}
else
{
function<ll(ll)>ck = [&](ll x)
{
ll fo = 0;
ll u = 0;
vector<ll>fs;
for (ll i = 1; i <= cnt; i++)
{
vis[a[i]] = 1;
fs.push_back(a[i]);
while (vis[u])
{
u++;
}
if (u >= x)
{
fo++;
u = 0;
for (auto j : fs)vis[j] = 0;
fs.clear();
}
}
for (auto j : fs)vis[j] = 0;
if (fo >= m)return 1;
else return 0;
};
ll l = 1, r = cnt+1;
while (l <= r)
{
ll mid = (l + r) >> 1;
if (ck(mid))
l = mid + 1;
else r = mid - 1;
}
cout << r << endl;
}
}
}
F. Hackers and Neural Networks
思路:感觉这道题没啥难度,可能是题意不太好理解?首先判断-1好弄,直接开个map<pair<ll,string>,ll>,然后遍历一遍目标数组看每个位置有没有对应字符串存在即可,有个位置没有对应字符串存在就可肯定构造不出来。有于每次是在空位随机复制字符串,这个答案问的是最坏情况的最小值。那么我们可以这么想,我们先找一个b数组,其要和目标数组所重合的字符串要最大。那么我们肯定花了n次才补全这个目标数组(有错误串),随后剩下的错误位置,我直接删一个,然后添加对应字符串即可(空位为1时,选定一个b数组,其添加的字符串肯定是相对应位置的字符串),那么答案就为n+(n-f)*2,f为某个b数组和目标数组的最大重合数。
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll long long
// #define lowbit(x) (x & -x)
//#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>;find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
ll lcm(ll x, ll y)
{
x /= gcd(x, y);
return y * x;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
struct ss
{
ll v, id;
friend bool operator<(const ss& a, const ss& b)
{
return a.v < b.v;
};
};
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为上下左右,后面四个为角落
const ll N = 50005;
int main()
{
fio();
ll t;
cin >> t;
while (t--)
{
ll n, m;
cin >> n >> m;
vector<string>a;
vector<ll>in(m+ 5, 0);
for (ll i = 1; i <= n; i++)
{
string f;
cin >> f;
a.push_back(f);
}
ll op = 0;
map<pair<ll, string>, ll>mp;
for (ll i = 1; i <= m; i++)
{
for (ll j = 1; j <= n; j++)
{
string f;
cin >> f;
if (f == a[j - 1])in[i]++, op = max(op, in[i]);
mp[{j - 1, f}]++;
}
}
ll ok = 0;
for (ll i = 0; i < a.size(); i++)
{
if (mp[{i, a[i]}] == 0)
{
ok = 1;
break;
}
}
if (ok)cout << -1 << endl;
else
{
ll j = a.size() - op;
if(op==a.size())cout<<op<<endl;
else cout << a.size()+j*2<< endl;
}
}
}
//3 132
//6 132465
//
G. Shorten the Array
思路:一看,不就是求区间两个数异或最大再套个区间限制呗。那么区间长度我二分不就好了,反正遍历下也才n * logn.然后怎么查区间两个数异或最大,我这里套了之前杭电多校的二进制trip树板子。其思想就是可持久化线段树(不了解得,可以去学学)。判断-1,就把每个数去询问全区间即可,n*31.还有就是二分遍历时,一定得把所有数作为询问数去问一遍。这里偷懒直接遍历了两次。
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll long long
// #define lowbit(x) (x & -x)
//#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>;find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
ll lcm(ll x, ll y)
{
x /= gcd(x, y);
return y * x;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
struct ss
{
ll v, id;
friend bool operator<(const ss& a, const ss& b)
{
return a.v < b.v;
};
};
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为上下左右,后面四个为角落
const ll N = 2e5 * 32 + 5;
ll tot = 0;
struct tree
{
ll ch[2];
ll sum;
}p[N];
void insert(ll &pos,ll f,ll x)//加入最大位置为30,那么实际需要(30+1+1)*2个点,因为要考虑二进制和累计,要比(最高位多一位+1)的容量
{
p[++tot]=p[pos];//等于前面一个数的数值,后面直接按照之前的路走,没走的地方依然保留着,这样相当于做了前缀和
pos=tot;
p[pos].sum++;
if(f<0)return;
ll v=(x>>f)&1;
insert(p[pos].ch[v],f-1,x);
}
ll query(ll l,ll r,ll x)
{
ll ans=0;
for(ll i=30;i>=0;i--)
{
ll k=((x>>i)&1)^1;//想要的二进制
if(p[p[r].ch[k]].sum-p[p[l].ch[k]].sum>0)//问有没有这个位置
{
ans|=(1ll<<i);
r=p[r].ch[k];//这里赋值无所谓,因为做了前缀,前面的先没(数值为0),要么同时没(数值均为0)
l=p[l].ch[k];
}
else
{
k^=1;
r=p[r].ch[k];
l=p[l].ch[k];
}
}
return ans;
}
int main()
{
ll t;
cin >> t;
while (t--)
{
tot = 0;
ll n, k;
cin >> n >> k;
vector<ll>b(n + 5);
vector<ll>a(n + 2);
a[0] = 0;
for (ll i = 1; i <= n; i++)
{
ll x;
cin >> x;
b[i] = x;
a[i] = a[i - 1];//copy下前面的状态
insert(a[i], 30, x);
}
ll ok = 0;
for (ll i = 1; i <= n; i++)
{
ll d = query(a[0], a[n], b[i]);
if (d >= k)ok = 1;
}
if (k == 0)
{
cout << 1 << endl;
continue;
}
if (ok == 0)
{
cout << -1 << endl;
continue;
}
ll l = 2, r = n;
function<ll(ll)>ck = [&](ll x)
{
ll ok = 0;
for (ll i = 1; i <= n - x + 1; i++)
{
ll d = query(a[i], a[i + x - 1], b[i]);
if (d >= k)
{
ok = 1;
break;
}
}
if (ok)return ok;
for (ll i = x; i <= n; i++)
{
ll d = query(a[i - x], a[i], b[i]);
if (d >= k)
{
ok = 1;
break;
}
}
return ok;
};
while (l < r)
{
ll mid = (l + r) >> 1;
if (ck(mid))
r = mid;
else l = mid + 1;
}
cout << r << endl;
}
}
上面代码也TLE了。这里给出nlogn时间复杂度算法:
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<cstring>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<unordered_map>
#include<string>
#include<bitset>
#define ll long long
// #define lowbit(x) (x & -x)
//#define endl "\n"// 交互题记得删除
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
// using namespace __gnu_pbds;
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
#define F first
#define S second
// tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>;find_by_order(k),找第k位(从小到大)的数字,order_of_key(x),x的排名
ll ksm(ll x, ll y)//快速幂
{
ll ans = 1;
x %= mod;
while (y)
{
if (y & 1)
{
ans = ans * x % mod;
}
x = x * x % mod;
y >>= 1;
}
return ans % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
ll lcm(ll x, ll y)
{
x /= gcd(x, y);
return y * x;
}
// inline ll read()//快读
// {
// register ll x = 0, f = 1;
// char c = getchar();
// while (c < '0' || c>'9')
// {
// if (c == '-') f = -1;
// c = getchar();
// }
// while (c >= '0' && c <= '9')
// {
// x = (x << 3) + (x << 1) + (c ^ 48); //等价于x*10+c-48,使用位运算加速
// c = getchar();
// }
// return x * f;
// }
struct ss
{
ll v, id;
friend bool operator<(const ss& a, const ss& b)
{
return a.v < b.v;
};
};
void fio()//加速流
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll e1[8] = { 0,1,0,-1,1,1,-1,-1 };
ll e2[8] = { 1,0,-1,0,1,-1,-1,1 };//前面四个为上下左右,后面四个为角落
const ll N = 2e5 * 32 + 5;
ll tot = 0;
struct tree
{
ll ch[2];
ll sum;
}p[N];
void insert(ll& pos, ll f, ll x)//注意存的是双下标啊
{
p[++tot] = p[pos];//复制一遍前面的
pos = tot;
p[pos].sum++;
if (f < 0)return;
ll v = (x >> f) & 1;
insert(p[tot].ch[v], f - 1, x);
}
ll query(ll l, ll r, ll x)
{
ll ans = 0;
for (ll i = 30; i >= 0; i--)
{
ll f = ((x >> i) & 1) ^ 1;
if (p[p[r].ch[f]].sum - p[p[l].ch[f]].sum > 0)
{
ans |= (1ll << i);
r = p[r].ch[f];
l = p[l].ch[f];
}
else
{
f ^= 1;
r = p[r].ch[f];
l = p[l].ch[f];
}
}
return ans;
}
int main()
{
ll t;
cin >> t;
while (t--)
{
tot = 0;
ll n, k;
cin >> n >> k;
vector<ll>b(n + 5);
vector<ll>a(n + 2);
a[0] = 0;
for (ll i = 1; i <= n; i++)
{
ll x;
cin >> x;
b[i] = x;
a[i] = a[i - 1];//copy下前面的状态
insert(a[i], 30, x);
}
ll ok = 0;
for (ll i = 1; i <= n; i++)
{
ll d = query(a[0], a[n], b[i]);
if (d >= k)ok = 1;
}
if (k == 0)
{
cout << 1 << endl;
continue;
}
if (ok == 0)
{
cout << -1 << endl;
continue;
}
ll j=1;
ll len=1e18;
for(ll i=1;i<=n;i++)
{
while(j+len-1<i)j++;
while(query(a[j-1],a[i],b[i])>=k)
{
len=min(len,i-j+1);
j++;
}
}
cout<<len<<endl;
}
}

浙公网安备 33010602011771号