Atcoder Tenka1 Programmer Contest 2019 题解
题面真简洁 qaq
C Stones
最终一定是连续一段 . 加上连续一段 # 。直接枚举断点记录前缀和统计即可。
1 #include<bits/stdc++.h> 2 #define rep(i,x,y) for (int i=(x);i<=(y);i++) 3 4 using namespace std; 5 6 const int N=2e5+10; 7 int n,cnt0[N],cnt1[N],ans; char s[N]; 8 9 int main(){ 10 scanf("%d%s",&n,s+1); 11 rep (i,1,n) cnt0[i]+=s[i]=='#',cnt1[i]+=s[i]=='.'; 12 rep (i,1,n) cnt0[i]+=cnt0[i-1],cnt1[i]+=cnt1[i-1]; 13 ans=n; 14 rep (i,0,n) ans=min(ans,cnt0[i]+cnt1[n]-cnt1[i]); 15 printf("%d\n",ans); 16 return 0; 17 }
D Three Colors
记 S 为总和,不妨设 $R>B,G$ ,那么有 $R\leq \frac S2$ 。考虑总方案减去 $R>\frac S2$ 的方案,后者用 f[i][j] 表示前 i 个数和为 j 的方案数,跑一遍 dp 即可。注意若存在 $R=B=\frac S2$ 这种情况需要去重。
1 #include<bits/stdc++.h> 2 #define rep(i,x,y) for (int i=(x);i<=(y);i++) 3 4 using namespace std; 5 6 const int N=311,mod=998244353; 7 int n,a[N],f[N][N*N],g[N][N*N],all,sum,res; 8 9 inline void upd(int &x,int y){x+=y; x-=x>=mod?mod:0;} 10 11 int main(){ 12 ios::sync_with_stdio(0); 13 cin>>n; 14 all=1; 15 rep (i,1,n) cin>>a[i],all=all*3ll%mod; 16 f[0][0]=1; 17 rep (i,1,n){ 18 rep (j,0,sum) if (f[i-1][j]){ 19 upd(f[i][j],f[i-1][j]*2ll%mod); 20 upd(f[i][j+a[i]],f[i-1][j]); 21 } 22 sum+=a[i]; 23 } 24 rep (i,(sum+1)>>1,sum) upd(res,f[n][i]); 25 if (!(sum&1)){ 26 sum=0; 27 g[0][0]=1; 28 rep (i,1,n){ 29 rep (j,0,sum) if (g[i-1][j]){ 30 upd(g[i][j],g[i-1][j]); 31 upd(g[i][j+a[i]],g[i-1][j]); 32 } 33 sum+=a[i]; 34 } 35 upd(res,mod-g[n][sum/2]); 36 } 37 upd(all,(mod-res)*3ll%mod); 38 cout<<all; 39 return 0; 40 }
E Polynomial Divisors
【开启翻译模式】
首先提取系数的 $\gcd$ 的所有质因子。
然后对于一个质数 $p\leq n$ ,整系数多项式 $f(x)$ 若满足所有 $x$ 代入的值都被 $p$ 整除,当且仅当在 $\mod p$ 意义下, $f$ 含有因式 $x^p-x$ 。那么我们只需要对所有质数 $p$ ,做一次模意义下多项式除法,检验余式是否为 0 即可。
证明:
- 充分性:根据费马小定理显然。
- 必要性:可以从如下事实证明:在 $\mod p$ 意义下 $0,1,...,p-1$ 均为 $f(x)$ 的根,那么 $f(x)$ 含有因式 $x(x-1)(x-2)...(x-(p-1))$ ,而 $x(x-1)(x-2)...(x-(p-1))$ 在 $\mod p$ 意义下和 $x^p-x$ 等价(如果它们不一致,我们可以得到它们的差并得到 $\leq p-1$ 次的含有 $p$ 个根的多项式,矛盾)。
1 #include<bits/stdc++.h> 2 #define rep(i,x,y) for (int i=(x);i<=(y);i++) 3 #define Vi vector<int> 4 5 using namespace std; 6 7 const int N=1e4+10; 8 int n,a[N],g,b[N],c[N]; Vi V; 9 10 bool is_prime(int x){ 11 for (int i=2;i*i<=x;i++) if (x%i==0) return 0; 12 return 1; 13 } 14 bool chk(int p){ 15 if (a[0]%p) return 0; 16 rep (i,0,n-1) b[i]=a[i+1]%p; 17 for (int i=n-1;i>=p-1;i--) (b[i-(p-1)]+=b[i])%=p,b[i]=0; 18 rep (i,0,n-1) if (b[i]%p) return 0; 19 return 1; 20 } 21 22 int main(){ 23 ios::sync_with_stdio(0); 24 cin>>n; 25 rep (i,0,n) cin>>a[i],g=__gcd(g,a[i]); 26 g<0?g=-g:0; reverse(a,a+n+1); 27 for (int i=2;i*i<=g;i++) 28 if (g%i==0){ 29 V.push_back(i); 30 while (g%i==0) g/=i; 31 } 32 if (g>1) V.push_back(g); 33 rep (i,2,n) if (is_prime(i)&&chk(i)) V.push_back(i); 34 sort(V.begin(),V.end()); 35 rep (i,0,(int)V.size()-1) if (!i||V[i]!=V[i-1]) cout<<V[i]<<'\n'; 36 return 0; 37 }
F Banned X
先不考虑 0 ,最后插入到 1, 2 中即可。
我们枚举 1, 2 构成的序列长度 n 。
考虑 1, 2 序列的合法方案,只有两种情况:
- 总和 $<x-1$
- 存在前缀和 $=x-1$
首先证明除了 $<x-1$ 的情况,若序列合法一定存在前缀和 $=x-1$ 。(这或许是个极其显然的命题,然而请原谅本人数学水平低下,若觉得显然可以直接跳过)
若序列和 $=x-1$ ,得证;
若序列和 $=x$ ,不合法,不予考虑;
若序列和 $>x$ :设数列 $sum_i$ 为序列前缀和,序列长度为 $N$ 。
若 $x=1$ ,有 $sum_0=0=x-1$ ,下面只考虑 $x>1$ 的情况。
考虑反证,假设不存在前缀和 $=x-1$ ,同时由于序列合法,可知也不存在前缀和 $=x$ 。那么有 $\forall \ i ,sum_i \neq x,sum_i\neq x-1$ ,即 $\forall\ i, sum_i<x-1 \ or \ sum_i>x$ 。由于前缀和具有单调递增性(在数值均 >0 的情况下),而 $sum_0=0,sum_N>x$ ,故 $\exists\ i\in [1,N], \ sum_{i-1}<x-1,sum_i>x$ ,也就是 $sum_i-sum_{i-1}>2$ ,和题中序列值域在 $[1,2]$ 矛盾。
故命题得证。
那么枚举和 $=x-1$ 的前缀长度。接下来考虑还有什么限制?
若序列 $a[1...k]$ 和为 $x-1$ 且 $k<n$ ,那么 $a[k+1]=2$ ,此时发现若 $a[1]=1$ ,那么存在子串 $a[2...k+1]$ 和为 $x-1$ 不合法,故 $a[1]=2$ 。所以以此类推,可以得到 $a[k+1...n]$ 均为 2 , $a[1...n-k]$ 同样均为 2 。
那么若 $n-k\leq k$ ,只需考虑长为 $k-(n-k)$ 的部分的方案数即可;若 $n-k>k$ ,此时发现唯一合法的情况为全部填 2 ,容易判断。
总时间复杂度 $\mathcal{O}(n^2)$ 。
1 #include<bits/stdc++.h> 2 #define rep(i,x,y) for (int i=(x);i<=(y);i++) 3 #define ll long long 4 5 using namespace std; 6 7 const int N=3010,mod=998244353; 8 int n,x,f[N][N<<1],fac[N],inv[N],ans; 9 10 inline void upd(int &x,int y){x+=y; x-=x>=mod?mod:0;} 11 12 void init(int n){ 13 fac[0]=fac[1]=inv[0]=inv[1]=1; 14 rep (i,2,n) fac[i]=(ll)fac[i-1]*i%mod,inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod; 15 rep (i,2,n) inv[i]=(ll)inv[i]*inv[i-1]%mod; 16 } 17 int C(int n,int m){return (ll)fac[n]*inv[m]%mod*inv[n-m]%mod;} 18 19 int main(){ 20 ios::sync_with_stdio(0); 21 cin>>n>>x; init(n); 22 f[0][0]=1; 23 rep (i,1,n) rep (j,1,x){ 24 upd(f[i][j],f[i-1][j-1]); 25 if (j>1) upd(f[i][j],f[i-1][j-2]); 26 } 27 rep (i,0,n){ 28 int res=0; 29 rep (j,0,x-2) upd(res,f[i][j]); 30 rep (j,0,i) 31 if (i-j<=j&&x-1-2*(i-j)>=0) upd(res,f[j-(i-j)][x-1-2*(i-j)]); 32 else if (i-j>j&&j*2==x-1) upd(res,1); 33 upd(ans,(ll)C(n,i)*res%mod); 34 } 35 printf("%d\n",ans); 36 return 0; 37 }