E. Exchanging Gifts
题意:
给定
n
n
n 个序列,每行一个,有两种给出方式
1
1
1
k
k
k
a
1
,
a
2
.
.
.
a
k
a_1,a_2...a_k
a1,a2...ak,
(
a
i
<
=
n
)
(a_i<=n)
(ai<=n) 表示第
i
i
i 个序列有
k
k
k 个数
2
2
2
x
x
x
y
y
y
(
x
,
y
<
=
i
−
1
)
(x,y<=i-1)
(x,y<=i−1) 表示第
i
i
i 个序列由第
x
x
x 个与
y
y
y 个按照
x
,
y
x,y
x,y 的顺序拼接而成
求第
n
n
n 个序列的最大满意度。
一个序列的满意度被定义为:一个序列重新排序前某个位置为
a
i
a_i
ai,排序后为
a
j
a_j
aj,如果
a
i
!
=
a
j
a_i!=a_j
ai!=aj,那么这个位置是满意位置,满意度为满意位置的个数
思路:
显然最大满意度讨论出现个数最多的一个数即可
设
s
u
m
sum
sum 为序列长度,
M
a
x
Max
Max 为出现最多一个数的次数
如果
M
a
x
∗
2
<
=
s
u
m
Max*2<=sum
Max∗2<=sum,则答案为
s
u
m
sum
sum
否则,会有
M
a
x
∗
2
−
s
u
m
Max*2-sum
Max∗2−sum 个位置不满意,因此答案为
s
u
m
−
(
M
a
x
∗
2
−
s
u
m
)
sum - (Max*2-sum)
sum−(Max∗2−sum)
主要是求第
n
n
n 个序列的长度以及出现最多的数的次数
开始考虑建图
D
F
S
DFS
DFS
然后这样写,就喜提
T
L
E
TLE
TLE 了
显然许多节点可能被重复遍历多次
这时记忆化搜索是没法写的,因为需要更新数据累计贡献
T
L
E
TLE
TLEcode:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 2e5 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
vector <int> v[maxn];
int cnt[maxn];
ll sum = 0;
vector <int> e[maxn];
void dfs(int x){
if(v[x].size()){
sum += v[x].size();
cnt[x] += 1;
return;
}
for(auto y : e[x]){
dfs(y);
}
}
void work()
{
cin >> n;
for(int i = 1; i <= n; ++i) v[i].clear(), cnt[i] = 0, e[i].clear();
sum = 0;
unordered_map <int, ll> ma;
for(int i = 1, op, k; i <= n; ++i){
cin >> op >> k;
if(op == 1){
for(int j = 1, x; j <= k; ++j){
cin >> x;
v[i].push_back(x);
}
}
else{
cin >> m;
e[i].push_back(k);
e[i].push_back(m);
}
}
dfs(n);
for(int i = 1; i <= n; ++i) if(v[i].size())
{
for(auto x : v[i]) ma[x] += cnt[i];
}
ll Max = 0;
for(auto x : ma) Max = max(Max, x.second);
// cout << sum << " " << Max << endl;
if(Max * 2 <= sum) cout << sum << endl;
else
{
cout << sum - (Max * 2 - sum) << endl;
}
}
int main()
{
ios::sync_with_stdio(0);
int TT;cin>>TT;while(TT--)
work();
return 0;
}
题解
题解给出的思路就很妙
初始设置
n
u
m
[
n
]
=
1
num[n]=1
num[n]=1,然后进行拓扑排序就可以类似
d
p
dp
dp 的计数转移到叶子节点,统计出
n
n
n 到某个叶子节点有多少条路,就是这个叶子节点最后的贡献次数
但是这里要注意,拓扑排序用的
d
e
g
deg
deg 并不是整个图中的
比如
1
,
2
1,2
1,2 这两个序列组成了序列
3
3
3,会从
3
3
3 向
1
,
2
1,2
1,2 连边。
1
,
2
1,2
1,2 又组成了序列
4
4
4,会从
4
4
4 向
1
,
2
1,2
1,2 连边,
4
4
4 是最终序列。那么按照倒着拓扑的思想,会从
4
4
4 出发,然后将
1
,
2
1,2
1,2 的入度
−
−
--
−−,但是我们会发现,此时
1
,
2
1,2
1,2 的入度并不为
0
0
0,所以不会被加入到队列中。因此我们需要先
D
F
S
DFS
DFS 一遍计算
d
e
g
deg
deg
这里给出一组数据
1
4
1 1 1
1 1 2
2 1 2
2 1 2
这道题用快读才能过,卡
I
/
O
I/O
I/O 太阴间了
A
C
AC
ACcode:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
using namespace std;
const int maxn = 1e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
// 快读板子
#define tpyeinput int
inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
inline void read(tpyeinput &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();}
int n, m;
vector <int> v[maxn], e[maxn];
queue <int> q;
int deg[maxn];
ll num[maxn];
ll sum = 0;
bool vis[maxn];
unordered_map <int, ll> ma;
void init(){
while(!q.empty()) q.pop();
for(int i = 1; i <= n; ++i)
v[i].clear(), e[i].clear(), vis[i] = deg[i] = num[i] = 0;
ma.clear();
}
void dfs(int x){
for(auto to : e[x])// 注意这里该如何统计 deg
{// 一个点可能被多个点指向,因此 deg 计数要在递归外边进行,放在里边只会计一次,显然不对
deg[to]++;
if(!vis[to]){
vis[to] = 1;
dfs(to);
}
}
}
void toposort(){
q.push(n);
while(!q.empty())
{
int x = q.front(); q.pop();
for(auto to : e[x]){
deg[to]--;
num[to] += num[x];
if(deg[to] == 0) q.push(to);
}
}
}
void work()
{
read(n);
init();
for(int i = 1, op, k; i <= n; ++i){
read(op); read(k);
if(op == 1){
for(int j = 1, x; j <= k; ++j){
read(x);
v[i].push_back(x);
}
}
else{
read(m);
e[i].push_back(k);
e[i].push_back(m);
}
}
dfs(n);
num[n] = 1;
toposort();
for(int i = 1; i <= n; ++i) if(v[i].size())
{
for(auto x : v[i]) ma[x] += num[i];
}
ll Max = 0, sum = 0;
for(auto x : ma) Max = max(Max, x.second), sum += x.second;
if(Max * 2 < sum) printf("%lld\n", sum);
else printf("%lld\n", sum - (Max * 2 - sum));
}
int main()
{
// ios::sync_with_stdio(0);
int TT;cin>>TT;while(TT--)
work();
return 0;
}
I. Interesting Permutation
题意:
传送门读题吧
思路:
显然可以判掉一些答案为
0
0
0 的情况
剩下的看题解
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 2e5 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
int h[maxn];
int f[maxn];
void work()
{
cin >> n;
for(int i = 1; i <= n; ++i) cin >> h[i];
for(int i = 2; i <= n; ++i) if(h[i-1] > h[i] || h[i] >= n || h[i-1] >= n){
cout << 0 << endl;return;
}
if(h[1]){
cout << 0 << endl;return;
}
ll ans = 1, cnt = 0;
for(int i = 2; i <= n; ++i){
if(h[i] == h[i-1]){
ans = ans * cnt % mod;
--cnt;
}
else if(h[i] > h[i-1]){
cnt = (cnt + h[i] - h[i-1] - 1 + mod) % mod;
ans = ans * 2 % mod;
}
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(0);
int TT;cin>>TT;while(TT--)
work();
return 0;
}