A-并查集
// 考察连通块,一眼想到并查集
// 对于并查集合 (a, b)合并之后合并(b, c) 与 (a, b)合并之后合并(a, c) 是没有区别的
// 所以拿第一个 Z 向后合并一遍,遇见 Z 、U 、 L、 I 就合并;
// 再拿第一个 U 按照规则向后合并一遍,再拿第一个 L 按照规则向后合并一遍,再拿第一个 I 按照规则向后合并一遍即可
// 时间复杂度为O(4 * n)
const int N = 1e6 + 10;
char str[N];
int p[N], s[N];
int find(int x)
{
if(x != p[x]) p[x] = find(p[x]);
return p[x];
}
int main()
{
IOS;
#ifdef LIBOLIN
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
cin >> (str + 1);
int n = strlen(str + 1);
int a, b, c, d;
a = b = c = d = n + 1;
for (int i = 1; i <= n; i++)
if (str[i] == 'Z')
{
a = i;
break;
}
for (int i = 1; i <= n; i++)
if (str[i] == 'U')
{
b = i;
break;
}
for (int i = 1; i <= n; i++)
if (str[i] == 'L')
{
c = i;
break;
}
for (int i = 1; i <= n; i++)
if (str[i] == 'I')
{
d = i;
break;
}
for(int i = 1; i <= n; i ++ )
p[i] = i, s[i] = 1;
for(int i = a + 1; i <= n; i ++ )
{
if(str[i] == 'Z' || str[i] == 'U' || str[i] == 'L' || str[i] == 'I')
{
int pa = find(a);
int pb = find(i);
if(pa != pb)
{
s[pb] += s[pa];
p[pa] = pb;
}
}
}
for(int i = b + 1; i <= n; i ++ )
{
if(str[i] == 'U' || str[i] == 'L' || str[i] == 'I')
{
int pa = find(b);
int pb = find(i);
if(pa != pb)
{
s[pb] += s[pa];
p[pa] = pb;
}
}
}
for(int i = c + 1; i <= n; i ++ )
{
if(str[i] == 'L' || str[i] == 'I')
{
int pa = find(c);
int pb = find(i);
if(pa != pb)
{
s[pb] += s[pa];
p[pa] = pb;
}
}
}
for(int i = d + 1; i <= n; i ++ )
{
if(str[i] == 'I')
{
int pa = find(d);
int pb = find(i);
if(pa != pb)
{
s[pb] += s[pa];
p[pa] = pb;
}
}
}
int ans = 0;
for(int i = 1; i <= n; i ++ )
{
ans = max(ans, s[i]);
}
cout << ans << endl;
return 0;
}
D-大盗
// 使用bitset容器,优化时间复杂度为O(n*k / 32)
bitset<50010> b = 1;
int main()
{
IOS;
#ifdef LIBOLIN
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int n, k;
cin >> n >> k;
for (int i = 0; i < n; i++)
{
int o, w;
cin >> o >> w;
if (o == 1)
{
b |= (b << w);
}
else
{
if (b[w])
{
b &= 1;
b[w] = 1;
}
else
{
b &= 1;
}
}
}
for (int i = k; i >= 0; i--)
{
if (b[i])
{
cout << i << endl;
break;
}
}
return 0;
}
I-密集
// 总结:具有单调性质的数据总可以使用二分
// 坑点:二分答案的时候不要把r开太大要不然会爆ll
const int N = 1e5 + 10;
ll n, k;
struct D
{
ll s;
ll v;
bool operator<(const struct D &W) const
{
return s < W.s;
}
} d[N];
bool check(ll t)
{
ll maxx = 0, ans = 0;
for (int i = 0; i < n; i++)
{
ll dis = d[i].s + d[i].v * t;
if(maxx > dis) ans ++;
maxx = max(maxx, dis);
}
return n - ans <= k;
}
int main()
{
IOS;
#ifdef LIBOLIN
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
cin >> n >> k;
for (int i = 0; i < n; i++)
cin >> d[i].s;
for (int i = 0; i < n; i++)
cin >> d[i].v;
sort(d, d + n);
ll l = 0, r = 1e9 + 10;
while (l < r)
{
ll mid = (l + r) / 2;
if (check(mid))
r = mid;
else
l = mid + 1;
}
if (l == 1e9 + 10)
cout << "Never!" << endl;
else
cout << l << endl;
return 0;
}