zoukankan      html  css  js  c++  java
  • AtCoder Grand Contest 046 简要题解

    从这里开始

      达成成就:不看 agc 题解补完一场 agc。

      感觉是我做过的最无聊的一场 agc,没有之一。让我来回顾一下我做了什么:

    • 大力猜结论
    • 大力猜结论
    • 好难啊,哦,没看到 respectively
    • 大力猜结论
    • 大力猜结论
    • #include "1338E",大力猜结论

      为什么这场出题人不学习一下隔壁 global round 9。

    Problem A Takahashikun, The Strider

      显然答案是 $frac{360}{(X, 360)}$。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    typedef bool boolean;
    
    template <typename T>
    boolean vmin(T& a, T b) {
    	return (a > b) ? (a = b, true) : (false);
    }
    template <typename T>
    boolean vmax(T& a, T b) {
    	return (a < b) ? (a = b, true) : (false);
    }
    
    template <typename T>
    T smax(T x) {
    	return x;
    }
    template <typename T, typename ...K>
    T smax(T a, const K &...args) {
    	return max(a, smax(args...));
    }
    
    template <typename T>
    T smin(T x) {
    	return x;
    }
    template <typename T, typename ...K>
    T smin(T a, const K &...args) {
    	return min(a, smin(args...));
    }
    
    // debugging lib
    
    #define VN(x) #x
    #define Vmsg(x) VN(x) << " = " << (x)
    #define printv(x) cerr << VN(x) << " = " << (x);
    #define debug(...) fprintf(stderr, __VA_ARGS__);
    
    template <typename A, typename B>
    ostream& operator << (ostream& os, const pair<A, B>& z) {
    	os << "(" << z.first << ", " << z.second << ')';
    	return os;
    }
    template <typename T>
    ostream& operator << (ostream& os, const vector<T>& a) {
    	boolean isfirst = true;
    	os << "{";
    	for (auto z : a) {
    		if (!isfirst) {
    			os << ", ";
    		}
    		os << z;
    		isfirst = false;
    	}
    	os << '}';
    	return os;
    }
    
    #define pii pair<int, int>
    #define pil pair<int, ll>
    #define pli pair<ll, int>
    #define ll long long
    #define ull unsigned long long
    
    const int inf = (signed) (~0u >> 2);
    const ll llf = (signed ll) (~0ull >> 2);
    
    #define pb push_back
    #define eb emplace_back
    #define fi first
    #define sc second
    
    template <typename T>
    int vsize(vector<T>& x) {
    	return (signed) x.size(); 
    }
    
    template <typename T>
    int discrete(T* a, int* b, int n) {
        vector<T> v(a + 1, a + n + 1);
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());
    	for (int i = 1; i <= n; i++) b[i] = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
    	return v.size();
    }
    
    mt19937 rng (time(NULL));
    
    int randint(int l, int r) {
    	return rng() % (r - l + 1) + l;
    }
    
    int X;
    
    int main() {
    	ios::sync_with_stdio(false);
    	cin.tie(0), cout.tie(0);
    	cin >> X;
    	cout << 360 / __gcd(X, 360) << '
    ';
    	return 0;
    }
    

    Problem B Extension

      考虑怎么判断一个局面是否可行。你相当于是要找一条折线只能向右和向上的折线,使得划开的两部分,一部分每列恰好有 1 个黑格子,一个每行恰好有 1 个黑格子。

      考虑对于必须要分给行的一个黑格子,那一列一定存在至少 2 个白格子。对于一列有至少 2 个白格子相当于是要求这个位置的折线高度至多为多少。

      从右往左考虑每列,记录最高的折线高度 dp。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    typedef bool boolean;
    
    template <typename T>
    boolean vmin(T& a, T b) {
    	return (a > b) ? (a = b, true) : (false);
    }
    template <typename T>
    boolean vmax(T& a, T b) {
    	return (a < b) ? (a = b, true) : (false);
    }
    
    template <typename T>
    T smax(T x) {
    	return x;
    }
    template <typename T, typename ...K>
    T smax(T a, const K &...args) {
    	return max(a, smax(args...));
    }
    
    template <typename T>
    T smin(T x) {
    	return x;
    }
    template <typename T, typename ...K>
    T smin(T a, const K &...args) {
    	return min(a, smin(args...));
    }
    
    // debugging lib
    
    #define VN(x) #x
    #define Vmsg(x) VN(x) << " = " << (x)
    #define printv(x) cerr << VN(x) << " = " << (x);
    #define debug(...) fprintf(stderr, __VA_ARGS__);
    
    template <typename A, typename B>
    ostream& operator << (ostream& os, const pair<A, B>& z) {
    	os << "(" << z.first << ", " << z.second << ')';
    	return os;
    }
    template <typename T>
    ostream& operator << (ostream& os, const vector<T>& a) {
    	boolean isfirst = true;
    	os << "{";
    	for (auto z : a) {
    		if (!isfirst) {
    			os << ", ";
    		}
    		os << z;
    		isfirst = false;
    	}
    	os << '}';
    	return os;
    }
    
    #define pii pair<int, int>
    #define pil pair<int, ll>
    #define pli pair<ll, int>
    #define ll long long
    #define ull unsigned long long
    
    const int inf = (signed) (~0u >> 2);
    const ll llf = (signed ll) (~0ull >> 2);
    
    #define pb push_back
    #define eb emplace_back
    #define fi first
    #define sc second
    
    template <typename T>
    int vsize(vector<T>& x) {
    	return (signed) x.size(); 
    }
    
    template <typename T>
    int discrete(T* a, int* b, int n) {
        vector<T> v(a + 1, a + n + 1);
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());
    	for (int i = 1; i <= n; i++) b[i] = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
    	return v.size();
    }
    
    mt19937 rng (time(NULL));
    
    int randint(int l, int r) {
    	return rng() % (r - l + 1) + l;
    }
    
    #define ll long long
    
    void exgcd(int a, int b, int& x, int& y) {
    	if (!b) {
    		x = 1, y = 0;
    	} else {
    		exgcd(b, a % b, y, x);
    		y -= (a / b) * x;
    	}
    }
    
    int inv(int a, int n) {
    	int x, y;
    	exgcd(a, n, x, y);
    	return (x < 0) ? (x + n) : (x);
    }
    
    const int Mod = 998244353;
    
    template <const int Mod = :: Mod>
    class Z {
    	public:
    		int v;
    
    		Z() : v(0) {	}
    		Z(int x) : v(x){	}
    		Z(ll x) : v(x % Mod) {	}
    
    		friend Z operator + (const Z& a, const Z& b) {
    			int x;
    			return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x));
    		}
    		friend Z operator - (const Z& a, const Z& b) {
    			int x;
    			return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x));
    		}
    		friend Z operator * (const Z& a, const Z& b) {
    			return Z(a.v * 1ll * b.v);
    		}
    		friend Z operator ~(const Z& a) {
    			return inv(a.v, Mod);
    		}
    		friend Z operator - (const Z& a) {
    			return Z(0) - a;
    		}
    		Z& operator += (Z b) {
    			return *this = *this + b;
    		}
    		Z& operator -= (Z b) {
    			return *this = *this - b;
    		}
    		Z& operator *= (Z b) {
    			return *this = *this * b;
    		}
    		friend boolean operator == (const Z& a, const Z& b) {
    			return a.v == b.v;
    		} 
    };
    
    Z<> qpow(Z<> a, int p) {
    	Z<> rt = Z<>(1), pa = a;
    	for ( ; p; p >>= 1, pa = pa * pa) {
    		if (p & 1) {
    			rt = rt * pa;
    		}
    	}
    	return rt;
    }
    
    typedef Z<> Zi;
    
    const int N = 3005;
    
    int A, B, C, D;
    Zi f[N][N];
    
    int main() {
    	ios::sync_with_stdio(false);
    	cin.tie(0), cout.tie(0);
    	cin >> A >> B >> C >> D;	
    	int da = C - A, db = D - B;
    	f[da + 1][db] = 1;
    	for (int i = da; i; i--) {
    		for (int j = 0; j <= db; j++) {
    			f[i][j] += f[i + 1][j] * (j + B);
    		}
    		Zi sum = 0;
    		for (int j = db; j--; ) {
    			sum = sum * (i + A) + f[i + 1][j + 1];
    			f[i][j] += sum * (j + B);	
    		}
    	}
    	Zi ans = 0;
    	for (int i = db; ~i; i--) {
    		ans = ans * A + f[1][i];
    	}
    	cout << ans.v << '
    ';
    	return 0;
    }
    

    Problem C Shift

      考虑 0 分割开的若干连续段,每次操作相当于把后面某个连续段长度 - 1,前面某个连续段长度 + 1。dp 即可。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    typedef bool boolean;
    
    template <typename T>
    boolean vmin(T& a, T b) {
      return (a > b) ? (a = b, true) : (false);
    }
    template <typename T>
    boolean vmax(T& a, T b) {
      return (a < b) ? (a = b, true) : (false);
    }
    
    template <typename T>
    T smax(T x) {
      return x;
    }
    template <typename T, typename ...K>
    T smax(T a, const K &...args) {
      return max(a, smax(args...));
    }
    
    template <typename T>
    T smin(T x) {
      return x;
    }
    template <typename T, typename ...K>
    T smin(T a, const K &...args) {
      return min(a, smin(args...));
    }
    
    // debugging lib
    
    #define VN(x) #x
    #define Vmsg(x) VN(x) << " = " << (x)
    #define printv(x) cerr << VN(x) << " = " << (x);
    #define debug(...) fprintf(stderr, __VA_ARGS__);
    
    template <typename A, typename B>
    ostream& operator << (ostream& os, const pair<A, B>& z) {
      os << "(" << z.first << ", " << z.second << ')';
      return os;
    }
    template <typename T>
    ostream& operator << (ostream& os, const vector<T>& a) {
      boolean isfirst = true;
      os << "{";
      for (auto z : a) {
        if (!isfirst) {
          os << ", ";
        }
        os << z;
        isfirst = false;
      }
      os << '}';
      return os;
    }
    
    #define pii pair<int, int>
    #define pil pair<int, ll>
    #define pli pair<ll, int>
    #define ll long long
    #define ull unsigned long long
    
    const int inf = (signed) (~0u >> 2);
    const ll llf = (signed ll) (~0ull >> 2);
    
    #define pb push_back
    #define eb emplace_back
    #define fi first
    #define sc second
    
    template <typename T>
    int vsize(vector<T>& x) {
      return (signed) x.size(); 
    }
    
    template <typename T>
    int discrete(T* a, int* b, int n) {
      vector<T> v(a + 1, a + n + 1);
      sort(v.begin(), v.end());
      v.erase(unique(v.begin(), v.end()), v.end());
      for (int i = 1; i <= n; i++) b[i] = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
      return v.size();
    }
    
    mt19937 rng (time(NULL));
    
    int randint(int l, int r) {
      return rng() % (r - l + 1) + l;
    }
    
    #define ll long long
    
    void exgcd(int a, int b, int& x, int& y) {
      if (!b) {
        x = 1, y = 0;
      } else {
        exgcd(b, a % b, y, x);
        y -= (a / b) * x;
      }
    }
    
    int inv(int a, int n) {
      int x, y;
      exgcd(a, n, x, y);
      return (x < 0) ? (x + n) : (x);
    }
    
    const int Mod = 998244353;
    
    template <const int Mod = :: Mod>
    class Z {
      public:
        int v;
    
        Z() : v(0) {	}
        Z(int x) : v(x){	}
        Z(ll x) : v(x % Mod) {	}
    
        friend Z operator + (const Z& a, const Z& b) {
          int x;
          return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x));
        }
        friend Z operator - (const Z& a, const Z& b) {
          int x;
          return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x));
        }
        friend Z operator * (const Z& a, const Z& b) {
          return Z(a.v * 1ll * b.v);
        }
        friend Z operator ~(const Z& a) {
          return inv(a.v, Mod);
        }
        friend Z operator - (const Z& a) {
          return Z(0) - a;
        }
        Z& operator += (Z b) {
          return *this = *this + b;
        }
        Z& operator -= (Z b) {
          return *this = *this - b;
        }
        Z& operator *= (Z b) {
          return *this = *this * b;
        }
        friend boolean operator == (const Z& a, const Z& b) {
          return a.v == b.v;
        } 
    };
    
    Z<> qpow(Z<> a, int p) {
      Z<> rt = Z<>(1), pa = a;
      for ( ; p; p >>= 1, pa = pa * pa) {
        if (p & 1) {
          rt = rt * pa;
        }
      }
      return rt;
    }
    
    typedef Z<> Zi;
    
    const int N = 305;
    
    int K;
    char s[N];
    Zi f[N][N], g[N][N];
    
    int main() {
      ios::sync_with_stdio(false);
      cin.tie(0), cout.tie(0);
      scanf("%s%d", s + 1, &K);
      int n = strlen(s + 1);
      K = min(K, n);
      vector<int> pos0;
      for (int i = 1; i <= n; i++) {
        if (s[i] == '0') {
          pos0.push_back(i);
        }
      }
      pos0.insert(pos0.begin(), 0);
      pos0.push_back(n + 1);
      vector<int> len;
      for (int i = 1; i < (signed) pos0.size(); i++) {
        len.push_back(pos0[i] - pos0[i - 1] - 1);
      }
      reverse(len.begin(), len.end());
      f[0][0] = 1;
      int suml = 0;
      for (auto l : len) {
        suml += l;
        for (int i = 0; i <= suml; i++) {
          memset(g[i], 0, (suml + 1) << 2);
        }
        for (int i = 0; i <= suml; i++) {
          for (int j = 0; j <= suml; j++) {
            g[i][j] = f[i][j];
            if (i && j) g[i][j] += g[i - 1][j - 1];
          }
        }
        for (int i = suml; i > l; i--) {
          for (int j = suml; j > l; j--) {
            g[i][j] -= g[i - l - 1][j - l - 1];
          }
        }
        for (int i = 0; i <= suml; i++) {
          Zi sum = 0;
          for (int j = suml; ~j; j--) {
            sum += f[i][j + 1];
            g[i][j] += sum;
          }
        }
        for (int i = 0; i <= suml; i++) {
          for (int j = 0; j <= suml; j++) {
            f[i][j] = g[i][j];
          }
        }
      }
      Zi ans = 0;
      for (int i = 0; i <= K; i++) {
        ans += f[i][0];
      }
      printf("%d
    ", ans.v);
      return 0;
    }
    

    Problem D Secret Passage

      显然主要问题是给定一个串 $s$ 判断是否可达。考虑把操作序列倒过来,相当于每次删除一个字符在前面这一个,然后再加入一个任意字符(这两个顺序可以颠倒),判定能否到达初始的串 $S$。

      感性理解一下,只用记录最长的等于 $S$ 的某个后缀的子序列长度,以及还有多少个 $0$,以及 $1$ 不在这里面。

      证明在路上了。

      显然填串 $s$ 的过程,和给定上述状态判断是否可行可以分开 dp。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    typedef bool boolean;
    
    template <typename T>
    boolean vmin(T& a, T b) {
      return (a > b) ? (a = b, true) : (false);
    }
    template <typename T>
    boolean vmax(T& a, T b) {
      return (a < b) ? (a = b, true) : (false);
    }
    
    template <typename T>
    T smax(T x) {
      return x;
    }
    template <typename T, typename ...K>
    T smax(T a, const K &...args) {
      return max(a, smax(args...));
    }
    
    template <typename T>
    T smin(T x) {
      return x;
    }
    template <typename T, typename ...K>
    T smin(T a, const K &...args) {
      return min(a, smin(args...));
    }
    
    // debugging lib
    
    #define VN(x) #x
    #define Vmsg(x) VN(x) << " = " << (x)
    #define printv(x) cerr << VN(x) << " = " << (x);
    #define debug(...) fprintf(stderr, __VA_ARGS__);
    
    template <typename A, typename B>
    ostream& operator << (ostream& os, const pair<A, B>& z) {
      os << "(" << z.first << ", " << z.second << ')';
      return os;
    }
    template <typename T>
    ostream& operator << (ostream& os, const vector<T>& a) {
      boolean isfirst = true;
      os << "{";
      for (auto z : a) {
        if (!isfirst) {
          os << ", ";
        }
        os << z;
        isfirst = false;
      }
      os << '}';
      return os;
    }
    
    #define pii pair<int, int>
    #define pil pair<int, ll>
    #define pli pair<ll, int>
    #define ll long long
    #define ull unsigned long long
    
    const int inf = (signed) (~0u >> 2);
    const ll llf = (signed ll) (~0ull >> 2);
    
    #define pb push_back
    #define eb emplace_back
    #define fi first
    #define sc second
    
    template <typename T>
    int vsize(vector<T>& x) {
      return (signed) x.size(); 
    }
    
    template <typename T>
    int discrete(T* a, int* b, int n) {
      vector<T> v(a + 1, a + n + 1);
      sort(v.begin(), v.end());
      v.erase(unique(v.begin(), v.end()), v.end());
      for (int i = 1; i <= n; i++) b[i] = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
      return v.size();
    }
    
    mt19937 rng (time(NULL));
    
    int randint(int l, int r) {
      return rng() % (r - l + 1) + l;
    }
    
    
    #define ll long long
    
    void exgcd(int a, int b, int& x, int& y) {
      if (!b) {
        x = 1, y = 0;
      } else {
        exgcd(b, a % b, y, x);
        y -= (a / b) * x;
      }
    }
    
    int inv(int a, int n) {
      int x, y;
      exgcd(a, n, x, y);
      return (x < 0) ? (x + n) : (x);
    }
    
    const int Mod = 998244353;
    
    template <const int Mod = :: Mod>
    class Z {
      public:
        int v;
    
        Z() : v(0) {	}
        Z(int x) : v(x){	}
        Z(ll x) : v(x % Mod) {	}
    
        friend Z operator + (const Z& a, const Z& b) {
          int x;
          return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x));
        }
        friend Z operator - (const Z& a, const Z& b) {
          int x;
          return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x));
        }
        friend Z operator * (const Z& a, const Z& b) {
          return Z(a.v * 1ll * b.v);
        }
        friend Z operator ~(const Z& a) {
          return inv(a.v, Mod);
        }
        friend Z operator - (const Z& a) {
          return Z(0) - a;
        }
        Z& operator += (Z b) {
          return *this = *this + b;
        }
        Z& operator -= (Z b) {
          return *this = *this - b;
        }
        Z& operator *= (Z b) {
          return *this = *this * b;
        }
        friend boolean operator == (const Z& a, const Z& b) {
          return a.v == b.v;
        } 
    };
    
    Z<> qpow(Z<> a, int p) {
      Z<> rt = Z<>(1), pa = a;
      for ( ; p; p >>= 1, pa = pa * pa) {
        if (p & 1) {
          rt = rt * pa;
        }
      }
      return rt;
    }
    
    typedef Z<> Zi;
    
    const int N = 305;
    
    int n;
    char s[N];
    bool f[N][N][N];
    Zi g[N][N][N];
    
    set<string> S;
    
    void check(string t) {
      int len = t.length();
      int p = n, x = 0, y = 0;
      for (int i = len; i--; ) {
        if (t[i] == s[p]) {
          p--;
        } else {
          (t[i] == '0' ? x : y)++;
        }
      }
      if (!f[p][x][y]) {
        cerr << t << '
    ';
      }
    }
    
    void dfs(string s) {
      if (S.count(s)) return;
      S.insert(s);
      check(s);
      if (s.length() < 2u)
        return;
      string t = s;
      t.erase(t.begin());
      t.erase(t.begin());
      char x = s[0], y = s[1];
      for (int i = 0; i < (signed) t.size(); i++) {
        string nt = t;
        nt.insert(nt.begin() + i, x);
        dfs(nt);
        nt = t;
        nt.insert(nt.begin() + i, y);
        dfs(nt);
      }
      string nt = t;
      nt += x;
      dfs(nt);
      nt = t;
      nt += y; 
      dfs(nt);
    }
    
    int main() {
      ios::sync_with_stdio(false);
      cin.tie(0), cout.tie(0);
      cin >> (s + 1);
      n = strlen(s + 1);
      f[0][0][0] = true;
      for (int i = 1; i <= n; i++) {
        for (int j = n; ~j; j--) {
          for (int k = n; ~k; k--) {
            if (i == n && !j && !k) continue;
            f[i][j][k] |= f[i - 1][j][k];
            if (s[i] == '0') f[i][j][k] |= f[i][j][k + 1];
            if (s[i] == '1') f[i][j][k] |= f[i][j + 1][k];
          } 
        }
        for (int j = 0; j <= n; j++) {
          for (int k = 0; k <= n; k++) {
            if (i > 1) {
              if ((s[i] == '0' || s[i - 1] == '0') && j) {
                f[i][j][k] |= f[i - 2][j - 1][k];
              }
              if ((s[i] == '0' && s[i - 1] == '0') && j) {
                f[i][j][k] |= f[i - 1][j - 1][k + 1];
              }
              if ((s[i] == '1' || s[i - 1] == '1') && k) {
                f[i][j][k] |= f[i - 2][j][k - 1];
              }
              if ((s[i] == '1' && s[i - 1] == '1') && k) {
                f[i][j][k] |= f[i - 1][j + 1][k - 1];
              }
            }
          }
        }
      }
      g[n + 1][0][0] = 1;
      for (int i = n + 1; i > 1; i--) {
        for (int j = 0; j <= n; j++) {
          for (int k = 0; k <= n; k++) {
            Zi v = g[i][j][k];
            if (!v.v)
              continue;
            g[i - 1][j][k] += v;
            if (s[i - 1] == '0')
              g[i][j][k + 1] += v;
            if (s[i - 1] == '1')
              g[i][j + 1][k] += v;
          }
        }
      }
      Zi ans = 0;
      for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= i; j++) {
          for (int k = 0; k <= i; k++) {
            if (f[i][j][k]) {
              ans += g[i + 1][j][k];
    //          cerr << g[i + 1][j][k].v << " " << i + 1 << " " << j << " "<< k << '
    ';
            }
          }
        }
      }
    //  dfs(string(s + 1));
      printf("%d
    ", ans.v);
      return 0;
    }
    

    Problem E Permutation Cover

      显然充要条件是 $max a_i leqslant 2min a_i$。

      考虑枚举每一位,枚举它的值,判断是否有一个合法序列的前缀为它。

      感性理解一下:只用判断补全一个包含它的排列,在再后面添加不超过 $K - 1$ 个数后,要求添加这些数现在都被某个排列覆盖,剩下的所有数能否构成合法序列。

      证明在路上了。

     Code

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 105;
    
    int n, m;
    vector<int> c, p;
    vector<bool> cov;
    vector<int> vmi, vpmi;
    
    bool chk0() {
      int mx = *max_element(c.begin(), c.end());
      int mi = *min_element(c.begin(), c.end());
      return mx <= 2 * mi;
    }
    
    int main() {
      scanf("%d", &m);
      c.resize(m);
      for (auto& x : c) {
        scanf("%d", &x);
        n += x;
      }
      if (!chk0()) {
        puts("-1");
        return 0;
      }
      p.resize(n);
      cov.resize(n, false);
      vmi.resize(n + 1, 0);
      vpmi.resize(n + 1, 0);
      for (int i = 0; i < n; i++) {
        for (int x = 0; x < m; x++) {
          if (!c[x]) continue;
          auto bc = c;
          auto bcov = cov;
          bc[x]--;
          p[i] = x;
          if (i >= m - 1) {
            vector<bool> vis(m, false);
            for (int j = 0; j < m; j++) {
              vis[p[i - j]] = true;
            }
            if (*min_element(vis.begin(), vis.end())) {
              fill(bcov.begin() + (i - m + 1), bcov.begin() + i + 1, true);
            }
          }
          int pr = i - 1;
          while (~pr && p[pr] != x)
            pr--;
          if (pr >= 0 && !*min_element(bcov.begin(), bcov.begin() + pr + 1)) {
            continue;
          }
          int R = i + 1;
          while (R && !bcov[R - 1])
            R--;
          bool flg = false;
          vector<bool> vis(m, false);
          int L = i + 1;
          while (L && !vis[p[L - 1]])
            vis[p[--L]] = true;
          int mi = 114514, mx = 0;
          for (int j = 0; j < m; j++) {
            mi = min(bc[j] - !vis[j], mi);
            mx = max(bc[j] - 1, mx);
          }
          int mip = i + 1;
          for (int j = L; j <= i; j++) {
            int y = p[j];
            if (bc[y] == mi) {
              mip = min(mip, j);
            }
          }
          vmi[L] = mi;
          vpmi[L] = mip;
          for (int j = L; j <= i; j++) {
            int y = p[j];
            if (bc[y] - 1 < mi) {
              vmi[j + 1] = bc[y] - 1; 
              vpmi[j + 1] = i + 1;
            } else {
              vmi[j + 1] = vmi[j];
              vpmi[j + 1] = vpmi[j];
            }
          }
          int mxp = i + 1;
          for (int j = i; j >= L; j--) {
            int y = p[j];
            if (bc[y] > mx) {
              mxp = j;
              mx = bc[y];
            }
            if (j <= R) {
              if (vmi[j] >= 0 && mx <= 2 * vmi[j] || (mx == 2 * vmi[j] + 1 && mxp <= vpmi[j])) {
                flg = true;
                break;
              }
            }
          }
          if (L > i && *max_element(bc.begin(), bc.end()) <= 2 * *min_element(bc.begin(), bc.end())) {
            flg = true;
          }
          if (flg) {
            cov = bcov;
            c = bc;  
            break;
          }
        }
      }
      assert(!*max_element(c.begin(), c.end()));
      assert(*min_element(cov.begin(), cov.end()));
      for (auto x : p) {
        printf("%d ", x + 1);
      }
      return 0;
    }
    

    Problem F Forbidden Tournament

      请先 get 一下前置结论

      先除去入度为 0 的点。设剩下的点中标号最小的为 $X$。

      因为 $in(X)$ 不存在环,所以设 $P_i$ 是所有有到 $X$ 的边的点,并且 $P_i$ 有边到 $P_{i - 1}$。

      因为 $out(X)$ 也不存在环,类似地定义 $Q_i$。

      设 $L = |in(X)|$

      不难发现和证明以下结论:

    • 存在边 $Q_1 ightarrow P_L$。
    • 如果存在边 $Q_i ightarrow P_j (i > 1)$,那么存在边 $Q_{i-1} ightarrow P_j$
    • 如果存在边 $Q_i ightarrow P_j (j < L)$,那么存在边 $Q_i ightarrow P_{j + 1}$
    • 上述条件是充分的

      然后枚举一下 $|in(X)|, |out(X)|$,做个简单 dp 就行了。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #ifdef local
    #define _assert(expr) assert(expr)
    #else
    #define _assert(expr)
    #endif
    
    int Mod = 998244353;
    
    typedef long long ll;
    
    void exgcd(int a, int b, int& x, int& y) {
      if (!b) {
        x = 1, y = 0;
      } else {
        exgcd(b, a % b, y, x);
        y -= (a / b) * x;
      }
    }
    int inv(int a, int Mod = ::Mod) {
      int x, y;
      exgcd(a, Mod, x, y);
      return (x < 0) ? (x + Mod) : x;
    }
    
    class Z {
      public:
        int v;
    
        Z() {	}
        Z(int v) : v(v) {
          _assert(v >= 0 && v < Mod);
        }
        Z(ll x) : v(x % Mod) {	}
    
        friend Z operator + (Z a, Z b) {
          int x;
          return Z((x = a.v + b.v) >= Mod ? x - Mod : x); 
        }
        friend Z operator - (Z a, Z b) {
          int x;
          return Z((x = a.v - b.v) < 0 ? x + Mod : x);
        }
        friend Z operator * (Z a, Z b) {
          return 1ll * a.v * b.v;
        }
        friend Z operator ~ (Z a) {
          _assert(a.v);
          return inv(a.v);
        }
        friend Z operator - (Z a) {
          return Z(0) - a;
        }
        Z& operator += (Z b) {
          return *this = *this + b;
        }
        Z& operator -= (Z b) {
          return *this = *this - b;
        }
        Z& operator *= (Z b) {
          return *this = *this * b;
        }
    };
    
    typedef Z Zi;
    
    Zi qpow(Zi a, int p) {
      if (p < 0)
        p += Mod - 1;
      Zi rt = 1;
      for ( ; p; p >>= 1, a *= a) {
        if (p & 1) {
          rt *= a;
        }
      }
      return rt;
    }
    Zi qpow(Zi a, ll p) {
      return qpow(a, (int) (p % (Mod - 1)));
    }
    
    const int N = 405;
    
    int n, K;
    
    vector<Zi> fac, _fac;
    
    void init_fac(int n) {
      fac.resize(n + 1);
      _fac.resize(n + 1);
      fac[0] = 1;
      for (int i = 1; i <= n; i++) {
        fac[i] = fac[i - 1] * i;
      }
      _fac[n] = ~fac[n];
      for (int i = n; i; i--) {
        _fac[i - 1] = _fac[i] * i;
      }
    }
    Zi comb(int n, int m) {
      return n < m ? 0 : fac[n] * _fac[m] * _fac[n - m];
    }
    
    Zi f[205][205];
    
    Zi calc(int n, int m, int bu, int bd) {
      for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
          f[i][j] = 0;
        }
      }
      for (int j = 0; j < m; j++) {
        f[0][j] = (j <= bu && j >= bd);
      }
      for (int i = 1; i < n; i++) {
        Zi sum = 0;
        for (int j = 0; j < m && j <= bu + i; j++) {
          sum += f[i - 1][j];
          if (j >= bd + i) {
            f[i][j] = sum;
          }
        }
      }
      Zi sum = 0;
      for (int j = max(bd + n - 1, 0); j < m && j < bu + n; j++) {
        sum += f[n - 1][j];
      }
      for (int i = 1; i < n; i++) {
        if (i + bu >= m) {
          sum += f[i][m - 1];
        }
      }
      return sum;
    }
    
    int main() {
      scanf("%d%d%d", &n, &K, &Mod);
      init_fac(405);
      K = n - 1 - K;
      Zi ans = !K;
      for (int sl = max(K, 1); sl < n; sl++) {
        for (int sr = max(K, 1); sl + sr < n; sr++) {
          Zi tmp = calc(sr, sl, sl - K, K - sr); 
    //      cerr << tmp.v << " ";
          tmp = tmp * ~Zi(sl + sr + 1);
          ans += tmp;
        }
      }
      ans *= fac[n];
      printf("%d
    ", ans.v);
      return 0;
    }
    

  • 相关阅读:
    033 流程控制之if判断
    032 基本运算符
    031 格式化输出的三种方式
    030 Python与用户交互
    029 解压缩
    028 布尔类型
    027 字典类型
    026 列表类型
    025 字符串类型
    023 数据类型基础
  • 原文地址:https://www.cnblogs.com/yyf0309/p/agc046.html
Copyright © 2011-2022 走看看