• 北京集训:20180314


    T1:


    大力矩阵乘法有40分,我也就会这么做了。
    以下为官方题解:


    (至今仍然不会常系数线性递推的蒟蒻......)
    40分代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 typedef long long int lli;
     6 using namespace std;
     7 const int maxm=210;
     8 const int mod=998244353,base=19260817;
     9 
    10 int now;
    11 struct Matrix {
    12     lli dat[maxm][maxm];
    13     Matrix(int tpe=0) {
    14         memset(dat,0,sizeof(dat));
    15         if( tpe ) for(int i=1;i<=now;i++) dat[i][i] = 1;
    16     }
    17     lli* operator [] (const int &x) {
    18         return dat[x];
    19     }
    20     friend Matrix operator * (const Matrix &a,const Matrix &b) {
    21         Matrix ret(0);
    22         for(int i=1;i<=now;i++)
    23             for(int j=1;j<=now;j++)
    24                 for(int k=1;k<=now;k++)
    25                     ( ret[i][j] += a.dat[i][k] * b.dat[k][j] % mod ) %= mod;
    26         return ret;
    27     }
    28 }ini,trans,ans;
    29 
    30 int m,a,n;
    31 inline void build() {
    32     ini = trans = Matrix(0);
    33     for(int i=1;i<=now;i++) trans[i][now] = ( a - 1 + mod ) % mod;
    34     for(int i=1;i<now;i++) trans[i+1][i] = 1;
    35     ini[1][1] = a % mod;
    36     for(int i=2;i<=now;i++) ini[1][i] = ini[1][i-1] * a % mod;
    37 }
    38 inline Matrix fastpow(Matrix base,int tim) {
    39     Matrix ret(1);
    40     while(tim) {
    41         if( tim & 1 ) ret = ret * base;
    42         if( tim >>= 1 ) base = base * base;
    43     }
    44     return ret;
    45 }
    46 inline lli calc(int nn) {
    47     now = nn , build();
    48     if( n <= now ) return ini[1][n];
    49     ans = ini * fastpow(trans,n-now);
    50     return ans[1][now];
    51 }
    52 inline lli getans() {
    53     lli ret = 0 , mul = 1;
    54     for(int i=0;i<=m;i++) {
    55         ret += calc(i) * mul % mod , 
    56         ret %= mod ,
    57         mul = mul * base % mod;
    58     }
    59     return ret;
    60 }
    61 
    62 int main() {
    63     scanf("%d%d%d",&m,&a,&n);
    64     printf("%lld
    ",getans());
    65     return 0;
    66 }
    View Code

    Commit@2018.03.15
    蒟蒻终于会常系数线性递推啦!
    首先我们有一个转移矩阵
    [0,0,a1]
    [1,0,a2]
    [0,1,a3]
    如果我们大力矩阵快速幂的话,复杂度是O(k^3logn)的,现在我们要想一个办法把他优化到O(k^2logn)

    我们知道矩阵A的特征多项式f(x)=|A-E*x|,其中E为单位矩阵。
    就是说,f(x)为矩阵A减去x倍单位矩阵后矩阵的行列式。
    然后我们有一个神奇的定理:如果我们把矩阵A当做自变量x带入f(x)中的话,我们会发现f(A)=0(证明什么的,感性理解吧)。
    这样的话,g(A)就等于g(A) mod f(A)。(考虑取模的意义,这很显然)
    而我们现在要求A的t次方,故g(A)=A^t,然后我们大力多项式取模一发就能用一个次数界为k的多项式表示g(A)。
    这个取模怎么做?我们可以快速幂倍增取模,利用FFT+多项式求逆可以做到klogk的复杂度,而这里我们直接k^2大力计算就好了。
    然后我们得到了一个多项式,怎么做?
    我们需要的答案为另一个矩阵B*g(A),也就是B*(g(A) mod f(A))。
    考虑这个多项式的意义,每一项B*A^p代表转移p次后获得的值。
    好,现在我们考虑怎么丢掉矩阵这个东西(因为一次矩乘就O(k^3)了)。
    如果我们大力预处理出原数列转移p次的值,然后用这个多项式的系数和预处理出的值相乘,不就直接得到我们需要的答案了吗?
    也就是说,我们的答案为:sigma(C[i]*PRE[i+k]),C为我们取模后的多项式。

    然而我们还不知道特征多项式怎么算。
    如果矩阵没什么性质的话,我们可以大力插值+高斯消元计算k+1个点值,然后用DFT或者拉格朗日插值算回去就好。
    然而,常系数线性递推的特征多项式是有性质的,他就是x^k-sigma(a[i]*x^(k-i))。
    此外你把系数放在右边和左边都是一样的,因为这两个矩阵互为转置,而转置矩阵的行列式相同。

    最后上代码(60分):

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define debug cout
     6 typedef long long int lli;
     7 using namespace std;
     8 const int maxn=4e2+1e1;
     9 const int mod=998244353,base=19260817;
    10 
    11 int k;
    12 inline lli fastpow(lli base,int tim) {
    13     lli ret = 1;
    14     while( tim ) {
    15         if( tim & 1 ) ret = ret * base % mod;
    16         if( tim >>= 1 ) base = base * base % mod;
    17     } 
    18     return ret;
    19 }
    20 inline lli inv(const lli &x) {
    21     return fastpow(x,mod-2);
    22 }
    23 struct Poly {
    24     lli dat[maxn];
    25     Poly() {
    26         memset(dat,0,sizeof(dat));
    27     }
    28     lli& operator [] (const int &x) {
    29         return dat[x];
    30     }
    31     const lli& operator [] (const int &x) const {
    32         return dat[x];
    33     }
    34     friend Poly operator * (const Poly &a,const Poly &b) {
    35         Poly ret;
    36         for(int i=0;i<k;i++)
    37             for(int j=0;j<k;j++)
    38                 ( ret[i+j] += a[i] * b[j] % mod ) %= mod;
    39         return ret;
    40     }
    41     friend Poly operator % (const Poly &a,const Poly &b) {
    42         Poly ret = a;
    43         int lst = k;
    44         while( !b[lst] ) --lst;
    45         for(int i=(k<<1);i>=lst;i--)
    46             if( ret[i] ) {
    47                 const lli mul = ret[i] * inv(b[lst]);
    48                 for(int t=0;t<=lst;t++)
    49                     ret[i-t] = ( ret[i-t] - b[lst-t] * mul % mod + mod ) % mod;
    50             }
    51         return ret;
    52     }
    53 }ini,trans,ans;
    54 
    55 lli ins[maxn];
    56 int m,a,n;
    57 
    58 inline Poly fastpow(Poly base,const Poly &mod,int tim) {
    59     Poly ret = base; --tim;
    60     while( tim ) {
    61         if( tim & 1 ) ret = ret * base % mod;
    62         if( tim >>= 1 ) base = base * base % mod;
    63     }
    64     return ret;
    65 }
    66 
    67 inline lli calc(int kk) {
    68     k = kk + 1;
    69     trans[kk] = 1;
    70     for(int i=0;i<kk;i++) trans[i] = ( 1 - a + mod ) % mod;
    71     if( n <= kk ) return fastpow(a,n);
    72     ins[0] = 1;
    73     for(int i=1;i<=kk;i++) ins[i] = ins[i-1] * a % mod;
    74     for(int i=kk+1;i<=kk<<1;i++) {
    75         ins[i] = 0;
    76         for(int t=1;t<=kk;t++) {
    77             ( ins[i] += ins[i-t] * ( a - 1 ) % mod ) %= mod;
    78         }
    79     }
    80     ini[1] = 1;
    81     ans = fastpow(ini,trans,n-kk);
    82     lli ret = 0;
    83     for(int i=0;i<k;i++) ( ret += ins[i+k-1] * ans[i] % mod ) %= mod;
    84     return ret;
    85 }
    86 
    87 int main() {
    88     static lli ans,mul=1;
    89     scanf("%d%d%d",&m,&a,&n); 
    90     for(int i=0;i<=m;i++) ( ans += mul * calc(i) % mod ) %= mod , ( mul *= base ) %= mod;
    91     printf("%lld
    ",ans);
    92     return 0;
    93 }
    View Code


    T2:


    这题部分分好多啊......
    前20分直接暴力。
    接下来20分先构建广义SAM然后倍增主席树。
    然后20分可以用LCT维护size。
    最后20分直接动态开点权值线段树好了。
    正解是后缀平衡树,并不会......
    另外广义SAM加大力pb_ds也可过80分......
    40分代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<queue>
      6 #define debug cout
      7 typedef long long int lli;
      8 using namespace std;
      9 
     10 int n,m;
     11 
     12 namespace Part1 { // 20 pts for brute force .
     13     const int maxn=2e2+1e1;
     14     int fa[maxn],in[maxn],len;
     15     char s[maxn],val[maxn];
     16     inline void add(int f,int i,char v) {
     17         fa[++n] = f , in[n] = i , val[n] = v;
     18     }
     19     inline void str(int pos) {
     20         len = 0;
     21         while(pos) s[++len] = val[pos] , pos = fa[pos];
     22     }
     23     inline bool judge(int p,int lim) {
     24         int ret = 0 , now = 1;
     25         while( p && now < len ) { // last char must be ''
     26             if( ret >= lim ) return 1;
     27             if( val[p] != s[now] ) return 0;
     28             ++ret , ++now , p = fa[p];
     29         }
     30         return ret >= lim;
     31     }
     32     inline int query(int p,int lim,int limin) {
     33         int ret = 0;
     34         str(p);
     35         for(int i=1;i<=n;i++)
     36             if( in[i] <= limin && judge(i,lim) )
     37                 ++ret;
     38         return ret;
     39     }
     40     inline void solve() {
     41         static int lastans = 1 , ans = 0;
     42         static char ss[10];
     43         for(int i=1;i<=n;i++) scanf("%d",in+i);
     44         for(int i=1,u,v;i<n;i++) {
     45             scanf("%d%d%s",&u,&v,ss);
     46             fa[v] = u , val[v] = *ss;
     47         }
     48         for(int i=1,o,u,l,r;i<=m;i++) {
     49             scanf("%d",&o);
     50             if( o == 0 ) {
     51                 scanf("%d%d%d",&u,&l,&r);
     52                 u ^= lastans;
     53                 ans = query(u,l,r) , printf("%d
    ",ans);
     54                 if( ans ) lastans = ans;
     55             } else if( o == 1 ) {
     56                 scanf("%d%d%s",&u,&l,ss);
     57                 u ^= lastans;
     58                 add(u,l,*ss);
     59             }
     60         }
     61     }
     62 }
     63 namespace Part4 {
     64     const int maxn=1e5+1e2;
     65     int lson[maxn<<4],rson[maxn<<4],sum[maxn<<4],cnt=1;
     66     inline void insert(int pos,int l,int r,int tar) {
     67         ++sum[pos];
     68         if( l == r ) return;
     69         const int mid = ( l + r ) >> 1;
     70         if( tar <= mid ) {
     71             if( !lson[pos] ) lson[pos] = ++cnt;
     72             insert(lson[pos],l,mid,tar);
     73         } else {
     74             if( !rson[pos] ) rson[pos] = ++cnt;
     75             insert(rson[pos],mid+1,r,tar);
     76         }
     77     }
     78     inline int query(int pos,int l,int r,int ll,int rr) {
     79         if( !pos ) return 0;
     80         if( ll <= l && r <= rr ) return sum[pos];
     81         const int mid = ( l + r ) >> 1;
     82         if( rr <= mid ) return query(lson[pos],l,mid,ll,rr);
     83         else if( ll > mid ) return query(rson[pos],mid+1,r,ll,rr);
     84         return query(lson[pos],l,mid,ll,rr) + query(rson[pos],mid+1,r,ll,rr);
     85     }
     86     inline void solve() {
     87         static int ans = 0;
     88         for(int i=1,x;i<=n;i++) {
     89             scanf("%d",&x);
     90             insert(1,1,1e9,x);
     91         }
     92         for(int i=1;i<n;i++) scanf("%*d%*d%*s");
     93         for(int i=1,o,l,r;i<=m;i++) {
     94             scanf("%d",&o);
     95             if( o == 0 ) {
     96                 scanf("%*d%*d%d",&r);
     97                 ans = query(1,1,1e9,1,r) , printf("%d
    ",ans);
     98             } else if( o == 1 ) {
     99                 scanf("%*d%d%*s",&l);
    100                 insert(1,1,1e9,l);
    101             }
    102         }
    103     }
    104 }
    105 
    106 int main() {
    107     scanf("%d%d",&n,&m);
    108     if( n <= 100 && m <= 100 ) Part1::solve();
    109     else Part4::solve();
    110 }
    View Code

    80分代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<ext/pb_ds/assoc_container.hpp>
     4 #define debug cerr
     5 using namespace std;
     6 using namespace __gnu_pbds;
     7 typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> Tree;
     8 const int maxn=8e4+1e2;
     9 
    10 struct InNode {
    11     int u,v,c,a;
    12     friend bool operator < (const InNode &a,const InNode &b) {
    13         return a.v < b.v;
    14     }
    15 }ins[maxn>>1];
    16 int ch[maxn<<1][4],len[maxn<<1],fa[maxn<<1],root,last;
    17 Tree sons[maxn<<1];
    18 int at[maxn];
    19 int n,m;
    20 
    21 inline int NewNode(int ll) {
    22     static int cnt = 0;
    23     len[++cnt] = ll;
    24     return cnt;
    25 }
    26 inline void pushson(int x,int v) {
    27     while(x) sons[x].insert(v) , x = fa[x];
    28 }
    29 inline void extend(int p,int x,int nv) {
    30     int np = NewNode(len[p]+1);
    31     while( p && !ch[p][x] ) ch[p][x] = np , p = fa[p];
    32     if( !p ) fa[np] = root;
    33     else {
    34         int q = ch[p][x];
    35         if( len[q] == len[p] + 1 ) fa[np] = q;
    36         else {
    37             int nq = NewNode(len[p]+1);
    38             memcpy(ch[nq],ch[q],sizeof(ch[q])) , fa[nq] = fa[q];
    39             fa[np] = fa[q] = nq;
    40             while( p && ch[p][x] == q ) ch[p][x] = nq , p = fa[p];
    41             sons[nq] = sons[q];
    42         }
    43     }
    44     pushson(np,nv);
    45     last = np;
    46 }
    47 inline int query(int pos,int lim,int mx) {
    48     if( lim > len[pos] ) return 0;
    49     while( fa[pos] && len[fa[pos]] >= lim ) pos = fa[pos];
    50     return sons[pos].order_of_key(mx+1);
    51 }
    52 inline void insert(int f,int x,int nv) {
    53     extend(at[f],x,nv) , at[++n] = last;
    54 }
    55 
    56 inline int cov(char x) {
    57     switch(x) {
    58         case 'A' : return 0;
    59         case 'T' : return 1;
    60         case 'C' : return 2;
    61         case 'G' : return 3;
    62     }
    63 }
    64 
    65 int main() {
    66     static int lim,lastans=1,ans,tp;
    67     static char ss[10];
    68     scanf("%d%d",&lim,&m);
    69     at[n=1] = last = root = NewNode(0);
    70     scanf("%d",&tp) , sons[1].insert(tp);
    71     for(int i=1;i<lim;i++) scanf("%d",&ins[i].a);
    72     for(int i=1;i<lim;i++) {
    73         scanf("%d%d%s",&ins[i].u,&ins[i].v,ss);
    74         ins[i].c = cov(*ss);
    75     }
    76     sort(ins+1,ins+lim);
    77     for(int i=1;i<lim;i++) insert(ins[i].u,ins[i].c,ins[i].a);
    78     for(int i=1,o,u,l,r,f,a;i<=m;i++) {
    79         scanf("%d",&o);
    80         if( o == 0 ) {
    81             scanf("%d%d%d",&u,&l,&r) ; u ^= lastans;
    82             ans = query(at[u],l,r) , printf("%d
    ",ans);
    83             if( ans ) lastans = ans;
    84         } else if( o == 1 ) {
    85             scanf("%d%d%s",&f,&a,ss) ; f ^= lastans;
    86             insert(f,cov(*ss),a);
    87         }
    88     }
    89     return 0;
    90 }
    View Code


    T3:


    这题我看错题爆零了。
    题意是每组里有x个则贡献为x/2。
    我认为是这组必须全了才贡献x/2,根本不可做。
    正解显然是一般图最大匹配。
    还有某大佬的乱搞算法,就是暴力贪心寻找奇偶性的增广路,也能AC。
    爆零代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<queue>
     6 #define debug cout
     7 typedef long long int lli;
     8 using namespace std;
     9 
    10 int n,m;
    11 
    12 namespace Part1 {
    13     const int maxn=6,maxs=(1<<6)+2,maxm=12;
    14     lli ned[maxm],val[maxm],f[maxm][maxs],ans;
    15     int full;
    16     
    17     inline void dp() {
    18         memset(f,0,sizeof(f)) , ans = **f;
    19         for(int i=1;i<=m;i++) {
    20             for(int j=0;j<full;j++) if( ! ( j & ned[i] ) ) f[i][j|ned[i]] = max( f[i][j|ned[i]] , f[i-1][j] + val[i] );
    21             for(int j=0;j<full;j++) f[i][j] = max( f[i][j] , f[i-1][j] );
    22         }
    23         for(int j=0;j<full;j++) ans = max( ans , f[m][j] );
    24     }
    25     inline void solve() {
    26         full = 1 << n;
    27         for(int i=1,x,t;i<=m;i++) {
    28             scanf("%d",&t) , val[i] = t >> 1 , ned[i] = 0;
    29             while( t-- ) scanf("%d",&x) , ned[i] |= ( 1 << ( x - 1 ) );
    30         }
    31         dp();
    32         printf("%lld
    ",ans);
    33     }
    34 }
    35 
    36 namespace Part2 {
    37     const int maxn=5e2+1e1,maxm=1.5e3+1e2;
    38     int s[maxn],t[maxm<<3],nxt[maxm<<3],f[maxm<<3],cnt;
    39     lli c[maxm<<3],dis[maxn];
    40     int inq[maxn],sou[maxn];
    41     int st,ed;
    42     inline void coredge(int from,int to,int flow,int cost) {
    43         t[++cnt] = to , f[cnt] = flow , c[cnt] = cost ,
    44         nxt[cnt] = s[from] , s[from] = cnt;
    45     }
    46     inline void singledge(int from,int to,int flow,int cost) {
    47         coredge(from,to,flow,cost) , coredge(to,from,0,-cost);
    48     }
    49     inline bool spfa() {
    50         memset(dis,0xef,sizeof(dis)) , dis[st] = 0;
    51         queue<int> q; q.push(st) , inq[st] = 1;
    52         while( q.size() ) {
    53             const int pos = q.front(); q.pop() , inq[pos] = 0;
    54             for(int at=s[pos];at;at=nxt[at])
    55                 if( f[at] && dis[t[at]] < dis[pos] + c[at] ) {
    56                     dis[t[at]] = dis[pos] + c[at] , sou[t[at]] = at;
    57                     if( !inq[t[at]] ) q.push(t[at]) , inq[t[at]] = 1;
    58                 }
    59         }
    60         return dis[ed] > 0;
    61     }
    62     inline int release() {
    63         int ret = 0x3f3f3f3f;
    64         for(int i=ed;i!=st;i=t[sou[i]^1]) ret = min( ret , f[sou[i]] );
    65         for(int i=ed;i!=st;i=t[sou[i]^1]) f[sou[i]] -= ret , f[sou[i]^1] += ret;
    66         return ret;
    67     }
    68     inline lli flow() {
    69         lli ret = 0;
    70         while( spfa() ) {
    71             ret += dis[ed] * release();
    72         }
    73         return ret;
    74     }
    75     inline void solve() {
    76         memset(s,0,sizeof(s)) , cnt = 0 , st = n + 1 , ed = n + 2;
    77         for(int i=1,t,x,y;i<=m;i++) {
    78             scanf("%d%d%d",&t,&x,&y);
    79             if( y & 1 ) swap(x,y);
    80             singledge(x,y,1,t>>1);
    81         }
    82         for(int i=1;i<=n;i++)
    83             if( i & 1 ) singledge(st,i,1,0);
    84             else singledge(i,ed,1,0);
    85         printf("%lld
    ",flow());
    86     }
    87 }
    88 
    89 int main() {
    90     while( scanf("%d%d",&n,&m) == 2 && ( n || m ) ) {
    91         if( n <= 6 && m <= 10 ) Part1::solve();
    92         else if( n <= 500 && m <= 1500 ) Part2::solve();
    93     }
    94     return 0;
    95 }
    View Code

    乱搞代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 const int maxn=3e3+1e2;
     4 
     5 struct Graph {
     6     int s[maxn],t[maxn<<1],nxt[maxn<<1],cnt;
     7     inline void addedge(int from,int to) {
     8         t[++cnt] = to , nxt[cnt] = s[from] , s[from] = cnt;
     9     }
    10     inline int start(int x) {
    11         return s[x];
    12     }
    13     inline void ite(int &x) {
    14         x = nxt[x];
    15     }
    16     inline void reset() {
    17         memset(s,0,sizeof(s)) , cnt = 0;
    18     }
    19 }g,rg;
    20 
    21 int bel[maxn],siz[maxn],visl[maxn],visr[maxn];
    22 int n,m;
    23 int tim;
    24 
    25 inline bool dfs(int pos) { // pos is a right point .
    26     if( ! ( siz[pos] & 1 ) ) return 1;
    27     for(int at=rg.start(pos);at;rg.ite(at)) {
    28         const int tar = rg.t[at];
    29         if( bel[tar] == pos ) {
    30             if( visl[tar] == tim ) continue;
    31             visl[tar] = tim;
    32             for(int at=g.start(tar);at;g.ite(at)) {
    33                 --siz[pos] , ++siz[g.t[at]] , bel[tar] = g.t[at];
    34                 if( dfs(g.t[at]) ) return 1;
    35                 ++siz[pos] , --siz[g.t[at]] , bel[tar] = pos;
    36             }
    37         } else {
    38             if( visr[bel[tar]] == tim ) continue;
    39             visr[bel[tar]] = tim;
    40             const int b = bel[tar];
    41             --siz[b] , ++siz[pos] , bel[tar] = pos;
    42             if( dfs(b) ) return 1;
    43             ++siz[b] , --siz[pos] , bel[tar] = b;
    44         }
    45     }
    46     return 0;
    47 }
    48 
    49 inline void init() {
    50     g.reset() , rg.reset();
    51     memset(bel,0,sizeof(bel)) , memset(siz,0,sizeof(siz)) ,
    52     memset(visl,0,sizeof(visl)) , memset(visr,0,sizeof(visr));
    53 }
    54 
    55 
    56 int main() {
    57     while( scanf("%d%d",&n,&m) == 2 && ( n || m ) ) {
    58         int ans = 0;
    59         init();
    60         for(int i=1,t,x;i<=m;i++) {
    61             scanf("%d",&t);
    62             while(t--) {
    63                 scanf("%d",&x) , g.addedge(x,i) , rg.addedge(i,x);
    64                 if( !bel[x] ) bel[x] = i , ++siz[i];
    65             }
    66         }
    67         for(int i=1;i<=m;i++) {
    68             visr[i] = tim = i , dfs(i);
    69         }
    70         for(int i=1;i<=m;i++) ans += ( siz[i] >> 1 );
    71         printf("%d
    ",ans);
    72     }
    73     return 0;
    74 }
    View Code


    既然我这么菜的话,还是赶紧滚粗学高考去吧。

  • 相关阅读:
    针式PKM的主要画面的功能简介
    程序员早日走向架构师的利器:针式PKM V8.01发布
    如何经营你的知识资产
    一般软件工程师怎样拥有更多的资产
    剪贴板的使用技巧
    不要给自己找不“深入学习”的理由了
    《小论无所事事》
    全国(1977年~2011年)历年参加高考人数和录取人数
    Sql Server中,文件批量重命名
    HTML斜线表头
  • 原文地址:https://www.cnblogs.com/Cmd2001/p/8570213.html
Copyright © 2020-2023  润新知