前言
最近codeforce打的不是很好,所以专门进行一次训练,下面题目的难度全在 1900 − 2100 1900-2100 1900−2100难度区间。
CF1475G Strange Beauty
题目链接:CF1475G Strange Beauty
题目大意:给定一个数组,求最少删去多少个数,使得剩下的所有元素互相整除。
数据范围:
1
≤
t
≤
10
,
1
≤
n
≤
2
∗
1
0
5
,
1
≤
a
[
i
]
≤
2
∗
1
0
5
1\le t\le 10,1\le n\le2*10^5,1\le a[i]\le 2*10^5
1≤t≤10,1≤n≤2∗105,1≤a[i]≤2∗105
题解:采取
d
p
dp
dp方法,
d
p
[
i
]
dp[i]
dp[i]表示以
i
i
i为最小元素的情况下,能最大包含多少元素。转移就是
d
p
[
i
]
=
(
m
a
x
i
∣
j
d
p
[
j
]
)
+
n
u
m
[
i
]
dp[i]=(\mathop{max}\limits_{i|j} dp[j])+num[i]
dp[i]=(i∣jmaxdp[j])+num[i]
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
AC代码:
#include<bits/stdc++.h>
#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
const ll N = 200000 + 10;
const int mod = 1e9 + 7;
int t, a[N],n,num[N],dp[N];
int mx = 200000;
int main()
{
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
read(t);
while (t--)
{
for (int i = 1; i <= mx; i++)num[i] = 0,dp[i]=0;
read(n);
for (int i = 1; i <= n; i++)
{
read(a[i]); num[a[i]]++;
}
int ans = 0;
for (int i = mx; i >=1; i--)
{
if (num[i] == 0)continue;
dp[i] = num[i];
for (int j = 2; j * i <= mx; j++)
{
dp[i] = max(dp[i], dp[i * j] + num[i]);
}
ans = max(ans, dp[i]);
}
printf("%d\n", n - ans);
}
return 0;
}
CF1475F Unusual Matrix
题目链接:CF1475F Unusual Matrix
题目大意:给定两个
n
∗
n
n*n
n∗n大小的
01
01
01数组
a
,
b
a,b
a,b。每次操作可以选择
a
a
a的一行或者一列对
1
1
1进行异或,问是否有可能让
a
=
b
a=b
a=b。
数据范围:
1
≤
n
≤
1000
1\le n \le 1000
1≤n≤1000
题解:采用并查集来求解,我们知道一行
o
r
or
or一列最多翻转一次。如果
a
[
i
]
[
j
]
=
=
b
[
i
]
[
j
]
a[i][j]==b[i][j]
a[i][j]==b[i][j]意味着第
i
i
i行和第
j
j
j列翻转的次数是相同的,否则两者翻转的次数是不同的。这种关系我们可以使用并查集来维护,只要发现了有矛盾就意味着不成立。如果要求输出操作序列,可以使用
2
−
s
a
t
2-sat
2−sat来求解。
AC代码:
#include<bits/stdc++.h>
#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
const ll N = 2000 + 10;
const int mod = 1e9 + 7;
int f[N * 10];
int t, n, a[N][N], b[N][N];
int find(int x)
{
return x == f[x] ? f[x] : f[x] = find(f[x]);
}
#define r(x) (x+n)
#define c(x) (x)
#define fm(x) (x+2*n)
int main()
{
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
read(t);
while (t--)
{
read(n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
scanf("%1d", &a[i][j]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
scanf("%1d", &b[i][j]);
for (int i = 1; i <= n; i++)
{
f[r(i)] = r(i);
f[fm(r(i))] = fm(r(i));
f[c(i)] = c(i);
f[fm(c(i))] = fm(c(i));
}
bool isok = 1;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (a[i][j] == b[i][j])
{
if (find(r(i)) == find(fm(c(j))) || find(c(j)) == find(fm(r(i))))isok = 0;
f[find(r(i))] = find(c(j));
f[find(fm(r(i)))] = find(fm(c(j)));
}
else
{
if (find(r(i)) == find((c(j))) || find(fm(c(j))) == find(fm(r(i))))isok = 0;
f[find(r(i))] = find(fm(c(j)));
f[find(fm(r(i)))] = find(c(j));
}
}
}
printf("%s\n", isok ? "YES" : "NO");
}
return 0;
}
CF1472G Moving to the Capital
题目链接:CF1472G Moving to the Capital
题目大意:emmm,好长好长,自己看翻译。
题解:很显然要先求出
d
d
d数组,然后我们处理最大使用一次的反边,其实就是不管
d
[
i
]
d[i]
d[i]和
d
[
t
o
]
d[to]
d[to]的大小,我们直接进行转移。最后我们来处理每一个点可以到达的最优点。
a
n
s
[
i
]
=
m
i
n
j
∈
i
能
达
到
的
集
合
a
n
s
[
j
]
ans[i]=\mathop{min}\limits_{j\in{i能达到的集合}}ans[j]
ans[i]=j∈i能达到的集合minans[j]
AC代码:
#include<bits/stdc++.h>
#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
const ll N = 200000 + 10;
const int mod = 1e9 + 7;
int t, n, m,d[N],ans[N];
vector<int>p[N];
bool vis[N];
void bfs(int u)
{
queue<int>pls;
pls.push(u);
d[u] = 0; vis[u] = 1;
while (pls.size())
{
int f = pls.front(); pls.pop(); vis[f] = 0;
for (auto to : p[f])
{
if (d[to] > d[f] + 1)
{
d[to] = d[f] + 1;
if (!vis[to])
{
pls.push(to);
vis[to] = 1;
}
}
}
}
}
void dfs(int u)
{
vis[u] = 1;
for (auto to : p[u])
{
if (d[to] <=d[u])continue;
if(!vis[to])dfs(to);
ans[u] = min(ans[u], ans[to]);
}
}
int main()
{
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
read(t);
while (t--)
{
read(n); read(m);
for (int i = 1; i <= n; i++)p[i].clear();
for (int i = 1; i <= n; i++)d[i] = 0x3f3f3f3f,ans[i]=d[i],vis[i]=0;
for (int i = 1; i <= m; i++)
{
int x, y; read(x), read(y); p[x].push_back(y);
}
bfs(1);
for (int i = 1; i <= n; i++)
{
ans[i] = d[i];
for (auto to : p[i])
{
ans[i] = min(ans[i], d[to]);
}
}
dfs(1);
for (int i = 1; i <= n; i++)printf("%d ", ans[i]);
printf("\n");
}
return 0;
}