CF1361-Solution
CF1361-Solution
A
发现合法性质弱,即若合法排序后直接输出\(pos\)即可。
考虑不合法,则不满足\(V_u = \left\{1...t_u-1\right\}, S_u= \left\{ t_v \ |\ v\ around\ u\right\}\ \text{s.t.}\ V_u \subset\ S_u, t_u \notin S_u\)时则不合法。
复杂度:\(O(nlog_2 n)\)
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
int n, m;
int head[N], nxt[N<<1], to[N<<1], cnt = 0;
void add(int u, int v) {
nxt[++cnt] = head[u];
head[u] = cnt;
to[cnt] = v;
}
int vis[N], in[N], t[N];
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m;
for(int i = 1; i <= m; ++i) {
int x, y; cin >> x >> y;
add(x, y), add(y, x);
}
vector<pair<int, int> > v;
for(int i = 1; i <= n; ++i) cin >> t[i];
for(int i = 1; i <= n; ++i) v.push_back({t[i], i});
for(int i = 1; i <= n; ++i) {
int sum = 0, fl = 0;
for(int j = head[i]; j; j = nxt[j]) {
if(in[t[to[j]]] != i) if(t[to[j]] == t[i]) {fl = 1; break;}else {if(t[to[j]] < t[i]) ++sum, (in[t[to[j]]] = i);};
}
if(sum != t[i] - 1 || fl) {
cout << -1;
return 0;
}
}
sort(v.begin(), v.end());
for(int i = 0; i < v.size(); ++i) cout << v[i].second << ' ';
}
B
考虑贪心的策略。
若\(p=1\),特判\(n\ mod\ 2\)即可。
对\(k_i\)排不升序,考虑逐渐放低\(p^{?}\)作为单位的指数,我们用\(\omega\)作为这个单位。
定义\(a\)作为较大集的和,\(b\)作为较小集的和,显然\(a\geq b\),另外定义\(\Delta = \frac{a - b}{\omega}\),显然\(\Delta \geq 0\)
那么再每一次降低单位时,我们在\(k_{i-1}\)与\(k_{i}\)之间不断对\(\Delta \times p\)
观察到在此过程中若存在\(\Delta \geq n - i + 1\)时可直接向后将数累加给\(b\),证明见\(1\)。
完成上述过程后,
-
若\(\Delta > 0\), 则向\(b\)累加,\(\Delta - 1\)
-
若\(\Delta = 0\), 则向\(a\)累加, \(\Delta = 1\)
复杂度:\(O(nlog_2 n + n log_p n)\)
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int poww(int a, int b) {
int c = 1;
while(b) {
if(b&1) c = 1ll * c * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return c;
}
void solve() {
static int n, p, ki[(int)1e6+5];
cin >> n >> p; for(int i = 1; i <= n; ++i) cin >> ki[i];
if(p == 1) {cout << (n & 1) << endl; return;}
sort(ki + 1, ki + 1 + n, greater<int>());
int a = 0, b = 0, del = 0;
for(int i = 1; i <= n; ++i) {
if(i > 1 && del) for(int j = ki[i - 1] - 1; j >= ki[i]; --j) if((del *= p) >= n - i + 1) {while(i <= n) b = (b + poww(p, ki[i++]))%mod; cout << (a - b + mod) % mod << endl; return;}
if(del) b = (b + poww(p, ki[i])) % mod, --del;
else a = (a + poww(p, ki[i])) % mod, ++del;
}
cout << (a - b + mod) % mod << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t; cin >> t;
while(t--) solve();
}
\(1\).证明
由于\(k_i\)不升,所以即使后面被当前\(\omega\)替换不会更劣,故可以贪心。
\(2\).关于时间复杂度
我们暂且忽略每一次操作后\(\Delta\)的\(1\)的浮动。
不妨令\(\omega = p^x\)
\(p^x \geq n - i + 1\)
缩放一下\(x = log_{p}p^x \geq log_pn \geq log_p{n-i+1}\)
浮动的干扰凭感觉不会对上界有太大影响。
C
考虑\(np\)解法,枚举\(k\),考虑如何检查可行性。
那么把\(\mod 2^k\)来连边,发现最后是个环,那么相当于把环上一些点粘起来,它必然是一条欧拉回路,记录输出即可。
复杂度:\(O(nk)\)
#include <bits/stdc++.h>
using namespace std;
const int N =(1<<20)+5;
int n, cnt = 0;
int head[N], to[N<<1], nxt[N<<1], in[N], x[N], y[N];
void add(int u, int v) {
nxt[++cnt] = head[u];
head[u] = cnt;
to[cnt] = v;
}
int vis[N];
void dfs(int x) {
vis[x] = 1;
for(int i = head[x]; i; i = nxt[i]) if(!vis[to[i]]) dfs(to[i]);
}
struct Node{int a,b,c,d;}toc[N<<1];
int h[N], nt[N<<1],ccnt=1;
void add(int u, Node v) {
nt[++ccnt]=h[u];h[u]=ccnt;toc[ccnt]=v;
}
vector<int> ans;
void dfs1(int x) {
for(int i = h[x];i;i=h[x]){
h[x]=nt[i];
Node*it=&toc[i];
if(!vis[it->d]) vis[it->d]=1,dfs1(it->c),ans.push_back(it->b),ans.push_back(it->a);
}
}
int sol(int t) {
int now = 1 << t;
cnt = 0;
memset(head, 0, sizeof(head));
for(int i = 0; i < now; ++i) vis[i] = 1;
memset(in, 0, sizeof(in));
for(int i = 1; i <= n; ++i) {
add(x[i] % now, y[i] % now),
add(y[i] % now, x[i] % now);
++in[x[i]%now]; ++in[y[i]%now];
vis[x[i] % now] = vis[y[i] % now] = 0;
}
dfs(x[1]%now);
for(int i = 0; i < now; ++i) {
if((in[i] & 1) || !vis[i]) {
return 0;
}
}
for(int i = 1; i <= n; ++i) {
int a = x[i] % now, b = y[i] % now;
add(a, {i*2-1,i*2,b,i});
add(b, {i*2,i*2-1,a,i});
} memset(vis,0,sizeof(vis)); dfs1(x[1] % now);
cout << t << endl;
for(int i = 0; i < ans.size(); ++i) cout << ans[i] << ' ';
return 1;
}
int main() {
cin >> n;
for(int i = 1; i <= n; ++i) {
cin >> x[i] >> y[i];
}
for(int i = 20; ~i; --i) {
if(sol(i) == 1) return 0;
}
puts("-1");
return 0;
}
D
建树后是一颗类菊花图。建树以斜率,按欧几里得距离排序即可。
考虑每个点到原点的贡献为
\(j\)为在其链上的排序。
分析正负发现选\(\leq \lfloor\frac{k}{2}\rfloor\)时选最远的那些,否则再选最近的那些。
考虑选值时增量不升,可处理出来排序取前\(k\)个。
复杂度:\(O(nlog_2n)\)
E
引理\(1\): 当以一个结点为根的\(dfs\)树上只有返祖边与树边,那么这个点合法。
由\(20\%\)这个强性质,可以随机选点来进行上述测试\(T\)次\(O(Tn)\)
若已经得到一个合法点,考虑其性质,在其\(dfs\)树上若一个非根结点的点子树内有多余一条对于它来说的返祖边,那么这个点是不合法的。
其次,若上述满足,则一个点是不合法的,当且仅当它对应的那条返祖边的另一端的祖先是不合法的,反之亦然,递归做即可,证明先鸽了。
复杂度:\(O(Tn)\)
\(T\)取\(50\)左右即可。
#include <bits/stdc++.h>
using namespace std;
int rnd() {return rand() << 15 | rand();}
int rdom(int l, int r) {
return l + int(1.0 * rnd() / (RAND_MAX << 15 | RAND_MAX) * (r - l) + 0.5);
}
const int N = 2e5 + 5;
int n, m;
int nxt[N << 1], to[N << 1], head[N], cnt = 0;
void add(int u, int v) {
nxt[++cnt] = head[u];
head[u] = cnt;
to[cnt] = v;
}
const int T = 53;
int inst;
int vis[N], be[N], bad[N], bl[N], dep[N];
void dfs1(int x) { // test rooted tree
if(!inst) return;
vis[x] = 1;
for(int i = head[x]; i; i = nxt[i]) {
if(!inst) return;
int y = to[i];
if(!vis[y]) dfs1(y);
else if(vis[y] == 2) inst = 0;
}
vis[x] = 2;
}
int check(int x) {
for(int i = 1; i <= n; ++i) vis[i] = 0, inst = 1;
dfs1(x);
return inst;
}
int dfs2(int x) {
vis[x] = 1, be[x] = x;
for(int y, i = head[x]; i; i = nxt[i]) {
if(!vis[y = to[i]]) {
dep[y] = dep[x] + 1;
bl[x] += dfs2(y);
if(dep[be[y]] < dep[be[x]]) be[x] = be[y];
} else {
++bl[x], --bl[y];
if(dep[y] < dep[be[x]]) be[x] = y;
}
}
if(bl[x] > 1) bad[x] = 1;
return bl[x];
}
void dfs3(int x) {
vis[x] = 1;
if(!bad[x] && bad[be[x]]) bad[x]=1;
for(int i=head[x];i;i=nxt[i]) if(!vis[to[i]]) dfs3(to[i]);
}
void sol() {
cnt = 0;
memset(head,0,sizeof(head));
cin >> n >> m;
for(int i = 1; i <= m; ++i) {
int u, v;
cin >> u >> v;
add(u, v);
}
int rt = -1;
for(int i = 1; i <= T; ++i) {
int x = rdom(1, n);
if(check(x)) {
rt = x;
break;
}
}
if(rt == -1) {
puts("-1");
return;
}
for(int i = 1; i <= n; ++i) vis[i] = bad[i] = dep[i] = be[i] = bl[i] = 0;
dfs2(rt);
for(int i = 1; i <= n; ++i) vis[i] = 0;
dfs3(rt);
vector<int> v;
for(int i = 1; i <= n; ++i) {
if(!bad[i]) v.push_back(i);
}
if((int)v.size() * 5 >= n) {
for(int i = 0; i < v.size(); ++i) cout << v[i] << ' ';
} else cout << "-1";
cout << endl;
}
int main() {
srand(12379801);
int t;
cin >> t;
while(t--) {
sol();
}
}

浙公网安备 33010602011771号