20200224省選模擬賽 總結

 

 

題解

至今都沒看懂

std:

#include <bits/stdc++.h>

inline int read() {
  int ret, cc, sign = 1;
  while (!isdigit(cc = getchar()))
    sign = cc == '-' ? -1 : sign;
  ret = cc - 48;
  while (isdigit(cc = getchar()))
    ret = cc - 48 + ret * 10;
  return ret * sign;
}

const int MOD = 998244353;
const int GEN = 3;
const int Inf = 0x3f3f3f3f;
const int MAXN = 3010;
inline int add(int a, int b) { return (a += b) >= MOD ? a - MOD : a; }
inline int sub(int a, int b) { return (a -= b) < 0 ? a + MOD : a; }
inline int mul(int a, int b) { return 1ll * a * b % MOD; }
inline void inc(int &a, int b) { (a += b) >= MOD ? a -= MOD : a; }
inline void dec(int &a, int b) { (a -= b) < 0 ? a += MOD : a; }
inline int qpow(int a, int p) {
  int ret = 1;
  p += (p < 0) * (MOD - 1);
  for (; p; p >>= 1, a = mul(a, a))
    if (p & 1) ret = mul(ret, a);
  return ret;
}

struct Graph {
  int to[MAXN];
  int head[MAXN];
  int next[MAXN];
  int e_cnt;
  inline void insert(int u, int v) {
    to[++e_cnt] = v, next[e_cnt] = head[u], head[u] = e_cnt;
    to[++e_cnt] = u, next[e_cnt] = head[v], head[v] = e_cnt;
  }
  Graph() : e_cnt(1) { }
} G;

typedef std::vector<int> Poly;
typedef std::vector<Poly> Func;
inline Poly operator * (const Poly&, const Poly&);
inline Poly operator + (const Poly&, const int&);
inline Poly operator + (const int&, const Poly&);
inline Poly operator + (const Poly&, const Poly&);
inline Poly operator - (const Poly&, const int&);
inline Poly operator - (const int&, const Poly&);
inline Poly operator - (const Poly&, const Poly&);
inline Poly operator * (const Poly&, const Poly&);
inline Poly operator + (const Poly&, const Poly&);
inline Poly operator - (const Poly&, const Poly&);
inline Poly Inverse(const Poly&);
inline Poly Ln(const Poly&);
inline Poly Exp(const Poly&);
inline Poly Pow(const Poly&, int);
inline Poly Sqrt(const Poly&);
inline void Print(const Poly&);
inline Poly Derivate(const Poly&);
inline Poly Integrate(const Poly&);
inline int Integrate(const Poly&, int, int);
inline int Eval(const Poly&, int);
inline int Eval(const Func&, int);
inline void Print(const Poly&);

const Poly X({0, 1});
int C[MAXN][MAXN];

inline Func operator * (const Func& lhs, const Func& rhs) {
  Func ret(std::max(lhs.size(), rhs.size()));
  for (size_t i = 0; i < ret.size(); ++i) {
    if (i < lhs.size() && i < rhs.size())
      ret[i] = lhs[i] * rhs[i];
    else if (i < lhs.size())
      ret[i] = lhs[i];
    else 
      ret[i] = rhs[i];
  }
  return ret;
}

inline Func operator * (const Func& lhs, const Poly& rhs) {
  Func ret(lhs.size());
  for (size_t i = 0; i < ret.size(); ++i)
    ret[i] = lhs[i] * rhs;
  return ret;
}

inline Func operator + (const Func& lhs, const Func& rhs) {
  Func ret(std::max(lhs.size(), rhs.size()));
  for (size_t i = 0; i < ret.size(); ++i) {
    ret[i] = (i < lhs.size() ? lhs[i] : Poly()) + 
             (i < rhs.size() ? rhs[i] : Poly());
  }
  return ret;
}

inline Func operator - (const Func& lhs, const Func& rhs) {
  Func ret(std::max(lhs.size(), rhs.size()));
  for (size_t i = 0; i < ret.size(); ++i) {
    ret[i] = (i < lhs.size() ? lhs[i] : Poly()) - 
             (i < rhs.size() ? rhs[i] : Poly());
  }
  return ret;
}

inline Poly Shift(const Poly &A, int x) {
  Poly a(A.size()), b(A.size());
  b[0] = 1, x = (x + MOD) % MOD;
  for (size_t i = 1; i < b.size(); ++i)
    b[i] = mul(b[i - 1], x);
  for (size_t i = 0; i < a.size(); ++i)
    for (size_t j = 0; j <= i; ++j) {
      inc(a[j], mul(A[i], mul(C[i][j], b[i - j])));
    }
  return a;
}

inline Func Shift(const Func& A, int x) {
  Func a;
  for (int i = 0; i + x < (int)(A.size()); ++i) {
    a.push_back(i + x >= 0 ? Shift(A[i + x], x) : Poly{0});
  }
  return a;
}

inline Func Integrate(const Func& lhs) {
  Func ret(lhs.size());
  for (size_t i = 0; i < ret.size(); ++i) {
    ret[i] = Integrate(lhs[i]);
    inc(ret[i][0], sub(i ? Eval(ret[i - 1], i) : 0, Eval(ret[i], i)));
  }
  return ret;
}

inline Func Derivate(const Func& lhs) {
  Func ret(lhs.size());
  for (size_t i = 0; i < lhs.size(); ++i)
    ret[i] = Derivate(lhs[i]);
  return ret;
}

inline Func Add(const Func& a) {
  if (a.empty()) return Func{X};
  Func ret(a.size() + 1);
  Func b = Integrate(a), c = Shift(b, -1);
  //Print(c);
  for (size_t i = 0; i < a.size(); ++i)
    ret[i] = b[i] - c[i];
  ret.back() = Poly{MOD - (int)a.size(), 1};
  ret.back() = ret.back() - c[a.size()];
  inc(ret.back()[0], Eval(b, a.size()));
  return ret;
}

inline Func Max(const Func& a, const Func& b) {
  return a * b;
}

inline int Eval(const Func& a, int x) {
  return Eval(a[std::max(std::min((int)a.size() - 1, x), 0)], x);
}

inline void Print(const Func& a) {
  for (auto p : a) {
    for (auto x : p)
      printf("%d ", x);
    puts("");
  }
  puts("");
}

Func F[MAXN];

Func Dp(int u, int fr) {
  if (!F[fr].empty()) 
    return F[fr];
  for (int e = G.head[u]; e; e = G.next[e]) 
    if (e != (fr ^ 1)) {
      F[fr] = Max(F[fr], Add(Dp(G.to[e], e)));
    }
  return F[fr];
}

inline int Calc(const Func& a) {
  int ret = 0;
  //Print(a);
  Func f1 = Integrate(a * X);
  inc(ret, sub(Eval(f1, 1), Eval(f1, 0)));
  f1 = Integrate(Integrate(Derivate(a) * X));
  inc(ret, sub(Eval(f1, 1), Eval(f1, 0)));
  //std::cerr << ret << std::endl;
  return ret;
}

inline int Calc(Func a, Func b) {
  int ret = 0;
  int lena = a.size(), lenb = b.size();
  int maxlen = std::max(lena, lenb);
  while (a.size() < maxlen + 5u) a.emplace_back(1, 1);
  while (b.size() < maxlen + 5u) b.emplace_back(1, 1);
  Func c, d, e, f, g;

  c = b * X;
  d = Integrate(c);
  e = Shift(d, 1) - d;
  d = Integrate(b);
  f = Shift(d, 1) - d;
  f = f * X;
  f = e - f - b * Poly{(MOD + 1) >> 1};
  g = Integrate(Derivate(a) * f);
  inc(ret, sub(Eval(g, lena), Eval(g, 0)));

  c = Shift(b, 1) - b;
  c = c * Poly{1, 1};
  d = Integrate(Derivate(b) * X);
  e = Shift(d, 1) - d;
  f = c - e;
  g = Integrate(Derivate(a) * f * X);
  inc(ret, sub(Eval(g, lena), Eval(g, 0)));

  c = a - Shift(a, -1);
  c = c * Poly{1, MOD - 1};
  d = Integrate(Derivate(a) * X);
  e = d - Shift(d, -1);
  f = c + e;
  g = Integrate(Derivate(b) * f * X);
  inc(ret, sub(Eval(g, lenb), Eval(g, 0)));

  return ret;
}

std::pair<int, int> E[MAXN];
inline int Calc(int x) {
  Func fx = Dp(E[x].first, x << 1 | 1);
  Func fy = Dp(E[x].second, x << 1);
  if (fx.empty() && fy.empty()) {
    return qpow(2, MOD - 2);
  } else if (fx.empty()) {
    return Calc(fy);
  } else if (fy.empty()) {
    return Calc(fx);
  } else {
    return add(Calc(fx, fy), Calc(fy, fx));
  }
}

int n;

int main() {

  freopen("expectation.in","r",stdin);
  freopen("expectation.out","w",stdout);
  n = read();
  for (int i = 1; i < n; ++i) {
    E[i].first = read(), E[i].second = read();
    G.insert(E[i].first, E[i].second);
  }
  for (int i = (C[0][0] = 1); i < MAXN; ++i)
    for (int j = (C[i][0] = 1); j <= i; ++j)
      C[i][j] = add(C[i - 1][j], C[i - 1][j - 1]);
  int ans = 0;
  for (int i = 1; i < n; ++i) 
    inc(ans, Calc(i));
  printf("%d\n", ans);
}

inline void Print(const Poly& rhs) {
  for (auto x : rhs)
    printf("%d ", x);
  puts("");
}

int rev[MAXN];
int W[MAXN];

inline int getrev(int n) {
  int len = 1, cnt = 0;
  while (len < n) len <<= 1, ++cnt;
  for (int i = 0; i < len; ++i)
    rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (cnt - 1));
  return len;
}

inline void NTT(Poly& a, int n, int opt) {
  a.resize(n);
  for (int i = 0; i < n; ++i)
    if (i < rev[i])
      std::swap(a[i], a[rev[i]]);
  W[0] = 1;
  for (int i = 1; i < n; i <<= 1) {
    int wn = qpow(GEN, opt * (MOD - 1) / (i << 1));
    for (int k = i - 2; k >= 0; k -= 2)
      W[k + 1] = mul(W[k] = W[k >> 1], wn);
    for (int j = 0, p = i << 1; j < n; j += p) {
      for (int k = 0; k < i; ++k) {
        int x = a[j + k], y = mul(W[k], a[j + k + i]);
        a[j + k] = add(x, y), a[j + k + i] = sub(x, y);
      }
    }
  }
  if (opt == -1)
    for (int i = 0, r = qpow(n, MOD - 2); i < n; ++i)
      a[i] = mul(a[i], r);
}

inline Poly operator * (const Poly& lhs, const Poly& rhs) {
  if (lhs.size() * rhs.size() <= 2000) {
    Poly ret(lhs.size() + rhs.size() - 1);
    for (size_t i = 0; i < lhs.size(); ++i)
      for (size_t j = 0; j < rhs.size(); ++j)
        inc(ret[i + j], mul(lhs[i], rhs[j]));
    return ret;
  }
  Poly A(lhs), B(rhs);
  int len = A.size() + B.size() - 1;
  int bln = getrev(len);
  NTT(A, bln, 1), NTT(B, bln, 1);
  for (int i = 0; i < bln; ++i)
    A[i] = mul(A[i], B[i]);
  NTT(A, bln, -1), A.resize(len);
  return A;
}

inline Poly operator + (const Poly& lhs, const Poly& rhs) {
  Poly ret(std::max(lhs.size(), rhs.size()));
  for (size_t i = 0; i < ret.size(); ++i)
    ret[i] = add(i < lhs.size() ? lhs[i] : 0, i < rhs.size() ? rhs[i] : 0);
  return ret;
}

inline Poly operator + (const Poly& lhs, const int& c) {
  Poly ret(lhs);
  inc(ret[0], c);
  return ret;
}
inline Poly operator + (const int& c, const Poly& rhs) {
  Poly ret(rhs);
  inc(ret[0], c);
  return ret;
}
inline Poly operator - (const Poly& lhs, const int& c) {
  Poly ret(lhs);
  dec(ret[0], c);
  return ret;
}
inline Poly operator - (const int& c, const Poly& rhs) {
  Poly ret(rhs);
  dec(ret[0], c);
  for (int &x : ret) x = MOD - x;
  return ret;
}

inline Poly operator - (const Poly& lhs, const Poly& rhs) {
  Poly ret(std::max(lhs.size(), rhs.size()));
  for (size_t i = 0; i < ret.size(); ++i)
    ret[i] = sub(i < lhs.size() ? lhs[i] : 0, i < rhs.size() ? rhs[i] : 0);
  return ret;
}

std::vector<int> getinv() {
  std::vector<int> inv(MAXN);
  inv[1] = 1;
  for (int i = 2; i < MAXN; ++i)
    inv[i] = mul(MOD - MOD / i, inv[MOD % i]);
  return inv;
}
std::vector<int> Inv = getinv();

inline Poly Derivate(const Poly& A) {
  Poly C(A.size() - 1);
  for (size_t i = 0; i < C.size(); ++i)
    C[i] = mul(i + 1, A[i + 1]);
  return C;
}

inline Poly Integrate(const Poly& A) {
  Poly C(A.size() + 1);
  for (size_t i = 1; i < C.size(); ++i)
    C[i] = mul(Inv[i], A[i - 1]);
  return C;
}

inline Poly Eval(const Poly& A, const Poly& x) {
  Poly ret(1, A.back());
  for (int i = (int)(A.size()) - 2; i >= 0; --i)
    ret = (ret * x) + A[i];
  return ret;
}

inline int Eval(const Poly& A, int x) {
  int ret = A.back();
  for (int i = (int)(A.size()) - 2; i >= 0; --i)
    ret = add(mul(ret, x), A[i]);
  return ret;
}

inline int Integrate(const Poly& A, int l, int r) {
  Poly C(Integrate(A));
  return sub(Eval(C, r), Eval(C, l));
}

inline Poly Inverse(const Poly& A) {
  Poly B(1, qpow(A[0], MOD - 2));
  int n = A.size() << 1;
  for (int i = 2; i < n; i <<= 1) {
    Poly C(A); C.resize(i);
    int len = getrev(i << 1);
    NTT(B, len, 1), NTT(C, len, 1);
    for (int j = 0; j < len; ++j)
      B[j] = mul(B[j], sub(2, mul(B[j], C[j])));
    NTT(B, len, -1), B.resize(i);
  }
  B.resize(A.size());
  return B;
}

inline Poly Ln(const Poly& A) {
  Poly C = Integrate(Derivate(A) * Inverse(A));
  C.resize(A.size());
  return C;
}

inline Poly Exp(const Poly& A) {
  Poly B(1, 1);
  int n = A.size() << 1;
  for (int i = 2; i < n; i <<= 1) {
    Poly C(A);
    C.resize(i), B.resize(i);
    B = B * (Poly(1, 1) - Ln(B) + C);
  }
  B.resize(A.size());
  return B;
}

inline Poly Pow(const Poly& A, int k) {
  Poly C(Ln(A));
  for (size_t i = 0; i < C.size(); ++i)
    C[i] = mul(C[i], k);
  return Exp(C);
}

inline Poly Sqrt(const Poly& A) {
  Poly C(A);
  int c = A[0], ic = qpow(c, MOD - 2);
  for (size_t i = 0; i < C.size(); ++i)
    C[i] = mul(C[i], ic);
  c = sqrt(c), C = Pow(C, Inv[2]);
  for (size_t i = 0; i < C.size(); ++i)
    C[i] = mul(C[i], c);
  return C;
}

 

 

 

 

 

 

 

 

題解

唯一比較有思路的題

很明顯,我們可以用矩陣乘法來優化DP的轉移過程

求答案的時候就用[0,0,0,0,....1]*逆向的轉移矩陣的逆矩陣的前綴積*正向的轉移矩陣的前綴積

但是一次矩陣乘法是53^3,直接T飛

於是開始觀察轉移矩陣的乘積有什麼規律

有一個不用找規律的比較簡單的方法

左邊放需要找出乘積的特徵的矩陣  右邊放一個全是未知元的矩陣

手算把它們乘起來

就可以直接看出規律,就避免硬代數據找規律

然後發現它們的規律就是一列等於所有的列的和,與所有列減去一列

前者可以簡單維護

對於後者我們只需要維護53標記,要用的時候再下放即可(就像懶標記)

然後我們不能把每個節點的矩陣保留下來

但是考慮到詢問的時候只需要用到正向矩陣的每行之和與逆矩陣的列之和

於是我們可以只保留這些有用的值

於是就過了

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1000005
#define M 52
const int mod=998244353;
char s[N];
int num[N];
int sum[N][M+2],inv[N][M+2];
int tsum[M+2],now[M+2][M+2],la[M+2];
int main()
{
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	int Q,a,b,p,q,r,n,i,j,tp,pa,pb,L,R;
	int ans=0;
	scanf("%s",s+1);n=strlen(s+1);
	scanf("%d%d%d%d%d%d",&Q,&a,&b,&p,&q,&r);
	for(i=1;i<=n;i++){
		if(s[i]>='A'&&s[i]<='Z')s[i]-='A';
		else s[i]-='a'-26;
		num[i]=s[i];
	}
	for(i=0;i<=M;i++)tsum[i]=now[i][i]=1;
	for(i=1;i<=n;i++){
		for(j=0;j<=M;j++){
			tp=now[j][num[i]];
			now[j][num[i]]=tsum[j];
			tsum[j]=(1ll*tsum[j]+1ll*now[j][num[i]]-1ll*tp+1ll*mod)%mod;
		}
		memcpy(sum[i],tsum,sizeof(tsum));
	}
	memset(now,0,sizeof(now));
	for(i=0;i<=M;i++)now[i][i]=1;
	for(i=1;i<=n;i++){
		for(j=0;j<=M;j++){
			now[num[i]][j]=(now[num[i]][j]+la[j])%mod;
			la[j]=(la[j]-now[num[i]][j]+mod)%mod;
			now[num[i]][j]=(now[num[i]][j]-la[j]+mod)%mod;
		}
		for(j=0;j<=M;j++)
			inv[i][j]=(now[M][j]+la[j])%mod;
	}
	for(i=1;i<=Q;i++){
		pa=a;pb=b;
		a=(1ll*p*pa+1ll*q*pb+1ll*ans+1ll*r)%mod;
		b=(1ll*p*pb+1ll*q*pa+1ll*ans+1ll*r)%mod;
		L=min(a%n,b%n)+1;
		R=max(a%n,b%n)+1;
		if(L==1){ans=sum[R][M];continue;}
		for(j=0,ans=0;j<=M;j++)
			ans=(1ll*ans+1ll*inv[L-1][j]*sum[R][j])%mod;
	}
	printf("%d\n",ans);
}

 

 

 

 

 

 

 

 

 

 

題解

似乎T3纔是最簡單的。。。

設f[i][j][k],表示走了i步,構成強連通分量的爲前j個點,1號點一共連通了k個點

注意要先耗在正向邊上(當然是在點1~k之間)

再耗在反向邊(在1~j之間)

所以一共可以耗(k*(k-1)+(j*j-1))/2

枚舉一下 l 即可

 

 

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 102
int f[N*N][N][N];
const int mod=998244353;
inline void add(int &x,int &y){x+=y;if(x>=mod)x-=mod;}
int main()
{
	freopen("counting.in","r",stdin);
	freopen("counting.out","w",stdout);
	int n,i,j,k,l;
	scanf("%d",&n);
	f[0][1][1]=1;
	for(i=0;i<=n*(n-1);i++){
		for(j=1;j<=min(i+1,n);j++){
			for(k=j;k<=min(i+1,n);k++){
				if(f[i][j][k]){
					if(i<=k+j-2&&k<n)
						add(f[i+1][j][k+1],f[i][j][k]);
					else if(((k*(k-1)+j*(j-1))>>1)>=i+1)
						add(f[i+1][j][k],f[i][j][k]);
					for(l=1;l<=k-j;l++)
						if(((k*(k-1)+(j+l)*(j+l-1))>>1)>=i+1)
							add(f[i+1][j+l][k],f[i][j][k]);
				}
			}
		}
	}
	for(i=1;i<=n*(n-1);i++){
		int ans=0;
		for(j=1;j<=min(i+1,n);j++)
			for(k=j;k<=min(i+1,n);k++){
				ans+=f[i][j][k];
				if(ans>=mod)ans-=mod;
			}
		printf("%d ",ans);
	}
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章