Atcoder Tenka1 Programmer Contest 2019 题解

link

题面真简洁 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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

F Banned X

先不考虑 0 ,最后插入到 1, 2 中即可。

我们枚举 1, 2 构成的序列长度 n 。

考虑 1, 2 序列的合法方案,只有两种情况:

  1. 总和 $<x-1$ 
  2. 存在前缀和 $=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 }
View Code
posted @ 2019-04-21 01:33 bestfy 阅读(...) 评论(...) 编辑 收藏