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

建树后是一颗类菊花图。建树以斜率,按欧几里得距离排序即可。

考虑每个点到原点的贡献为

\[dist_x \times ((k - j) - (j - 1)) \]

\(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();
   }
}

F

posted @ 2020-11-12 18:14  Rimbaud  阅读(75)  评论(0)    收藏  举报