Cmd2001的毒瘤水题题解

怕不是我再不写题解这题就该成没人做也没人会的千古谜题了......

T1:


仔细分析题面,发现相同就是广义SAM上节点相同,相似就是广义SAM上为从根到某个点路径的前缀。、
直接SAM上跑从根开始,每个点下界为1的最小流即可。
代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<map>
  6 #include<queue>
  7 #define debug cout
  8 using namespace std;
  9 const int maxn=5e3+1e2;
 10 const int inf=0x3f3f3f3f;
 11   
 12 int in[maxn],n,ans,sum;
 13   
 14 namespace NetworkFlow {
 15     int s[maxn<<2],t[maxn<<6],nxt[maxn<<6],f[maxn<<6],dep[maxn<<2],deg[maxn<<2],cnt=1;
 16     int bak[maxn<<2],bcnt;
 17     int st,ed,_s,_t;
 18     inline void coredge(int from,int to,int flow) {
 19         t[++cnt] = to , f[cnt] = flow ,
 20         nxt[cnt] = s[from] , s[from] = cnt;
 21     }
 22     inline void singledge(int from,int to,int flow) {
 23         coredge(from,to,flow) , coredge(to,from,0);
 24     }
 25     inline bool bfs() {
 26         memset(dep,-1,sizeof(dep)) , dep[st] = 0;
 27         queue<int> q; q.push(st);
 28         while( q.size() ) {
 29             const int pos = q.front(); q.pop();
 30             for(int at=s[pos];at;at=nxt[at])
 31                 if( f[at] && !~dep[t[at]] ) {
 32                     dep[t[at]] = dep[pos] + 1 , q.push(t[at]);
 33                 }
 34         }
 35         return ~dep[ed];
 36     }
 37     inline int dfs(int pos,int flow) {
 38         if( pos == ed ) return flow;
 39         int ret = 0 , now = 0;
 40         for(int at=s[pos];at;at=nxt[at])
 41             if( f[at] && dep[t[at]] > dep[pos] ) {
 42                 now = dfs(t[at],min(flow,f[at])) ,
 43                 ret += now , flow -= now ,
 44                 f[at] -= now , f[at^1] += now;
 45                 if( !flow ) return ret;
 46             }
 47         if( !ret ) dep[pos] = -1;
 48         return ret;
 49     }
 50     inline int dinic() {
 51         int ret = 0 , now = 0;
 52         while( bfs() ) {
 53             while( ( now = dfs(st,inf) ) )
 54                 ret += now;
 55         }
 56         return ret;
 57     }
 58     inline int findflow() {
 59         for(int at=s[_t];at;at=nxt[at])
 60             if( t[at] == _s ) return f[at^1];
 61     }
 62     inline void backup() {
 63         memcpy(bak,s,sizeof(s)) , bcnt = cnt;
 64     }
 65     inline void restore() {
 66         memcpy(s,bak,sizeof(bak)) , cnt = bcnt;
 67     }
 68 }
 69   
 70 namespace SAM {
 71     map<int,int> ch[maxn<<1];
 72     int fa[maxn<<1],len[maxn<<1],root,last,cnt;
 73       
 74     inline int NewNode(int ll) {
 75         len[++cnt] = ll;
 76         return cnt;
 77     }
 78     inline void extend(int x) {
 79         int p = last;
 80         int np = NewNode(len[p]+1);
 81         while( p && ch[p].find(x) == ch[p].end() ) ch[p][x] = np , p = fa[p];
 82         if( !p ) fa[np] = root;
 83         else {
 84             int q = ch[p][x];
 85             if( len[q] == len[p] + 1 ) fa[np] = q;
 86             else {
 87                 int nq = NewNode(len[p]+1);
 88                 ch[nq] = ch[q] , fa[nq] = fa[q];
 89                 fa[np] = fa[q] = nq;
 90                 while( p && ch[p][x] == q ) ch[p][x] = nq , p = fa[p];
 91             }
 92         }
 93         last = np;
 94     }
 95     inline void Ex_extend(int* sou,int li) {
 96         last = root;
 97         for(int i=1;i<=li;i++) {
 98             if( ch[last].find(sou[i]) != ch[last].end() ) last = ch[last][sou[i]];
 99             else extend(sou[i]);
100         }
101     }
102 }
103   
104 inline void build() {
105     using SAM::ch;using SAM::cnt;
106     using namespace NetworkFlow;
107     _s = cnt * 2 + 1 , _t = _s + 1 , st = _t + 1 , ed = st + 1;
108     #define cov(x) (x+cnt)
109     for(int i=1;i<=cnt;i++) {
110         if( i != 1 ) ++deg[i] , --deg[cov(i)];
111         for(map<int,int>::iterator it=ch[i].begin();it!=ch[i].end();it++) {
112             const int tar = it->second;
113             if( i == 1 ) singledge(_s,tar,1);
114             else singledge(cov(i),tar,1);
115         }
116         if( i != 1 ) singledge(cov(i),_t,1);
117     }
118     backup();
119     for(int i=1;i<=_t;i++) {
120         if( !deg[i] ) continue;
121         if( deg[i] > 0 ) singledge(i,ed,deg[i]) , sum += deg[i];
122         else singledge(st,i,-deg[i]);
123     }
124     singledge(_t,_s,inf);
125 }
126 inline int getans() {
127     using namespace NetworkFlow;
128     int d = dinic();
129     if( d != sum ) return -1; // No solution .
130     int ret = findflow();
131     restore();
132     st = _t , ed = _s;
133     int dd = dinic();
134     return ret - dd;
135 }
136  
137 int main() {
138     static int m;
139     SAM::root = SAM::NewNode(0);
140     scanf("%d",&m);
141     while(m--) {
142         scanf("%d",&n);
143         for(int i=1;i<=n;i++) scanf("%d",in+i);
144         SAM::Ex_extend(in,n);
145     }
146     build();
147     ans = getans();
148     printf("%d\n",ans);
149     return 0;
150 }
View Code

 


T2:


观察操作数量特点,发现可持久化块状数组可过。
代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int maxn=1e6+1e2,maxb=1e3,maxu=1e4+1e2,maxr=1e5+1e2;
  7 
  8 inline int* NewArray() {
  9     static const int maxu = 1e4 + 1e3 + 10;
 10     static int dat[maxu][maxb],cnt;
 11     return dat[cnt++];
 12 }
 13 
 14 struct PersistentBlockedArray {
 15     int* p[maxb];
 16     inline void insert(int pos,int x) { // insert into this array .
 17         if( !p[pos/maxb] ) p[pos/maxb] = NewArray();
 18         p[pos/maxb][pos%maxb] = x;
 19     }
 20     inline void modify(int pos,int x) {
 21         int* t = NewArray();
 22         memcpy(t,p[pos/maxb],sizeof(int)*maxb);
 23         t[pos%maxb] = x , p[pos/maxb] = t;
 24     }
 25     inline int query(int pos) {
 26         return p[pos/maxb][pos%maxb];
 27     }
 28 }dat[maxu];
 29 
 30 int ptr[maxu+maxr],now,cnt;
 31 
 32 inline void roll(int tar) {
 33     ptr[++now] = ptr[tar];
 34 }
 35 inline void modify(int pos,int x) {
 36     dat[++cnt] = dat[ptr[now]] , ptr[now] = cnt;
 37     dat[ptr[now]].modify(pos,x);
 38 }
 39 inline int query(int pos) {
 40     return dat[ptr[now]].query(pos);
 41 }
 42 
 43 namespace IO {
 44     const int BS = 1 << 21;
 45     char ibuf[BS],obuf[BS],*ist,*ied,*oed=obuf;
 46     inline char nextchar() {
 47         if( ist == ied ) ied = ibuf + fread(ist=ibuf,1,BS,stdin);
 48         return ist == ied ? -1 : *ist++;
 49     }
 50     inline int getint() {
 51         int ret = 0 , ch;
 52         while( !isdigit(ch=nextchar()) );
 53         do ret=ret*10+ch-'0'; while( isdigit(ch=nextchar()) );
 54         return ret;
 55     }
 56     inline void getstr(char* s) {
 57         char ch;
 58         while( !isalpha(ch=nextchar()) ) ;
 59         do *s++=ch; while( isalpha(ch=nextchar()) );
 60     }
 61     inline void flush() {
 62         //cerr<<"in flush delta = "<<oed-obuf<<endl;
 63         fwrite(obuf,1,oed-obuf,stdout) , oed = obuf;
 64     }
 65     inline void printchar(const char &x) {
 66         *oed++ = x;
 67         //cerr<<"delta = "<<oed-obuf<<endl;
 68         if( oed == obuf + BS ) flush();
 69     }
 70     inline void printint(int x) {
 71         //cerr<<"x = "<<x<<endl;
 72         static int stk[30],top;
 73         if( !x ) printchar('0');
 74         else {
 75             top = 0;
 76             while(x) stk[++top] = x % 10 , x /= 10;
 77             while(top) printchar('0'+stk[top--]);
 78         }
 79         printchar('\n');
 80     }
 81 }
 82 using IO::getint;
 83 using IO::printint;
 84 using IO::getstr;
 85 using IO::flush;
 86 
 87 int main() {
 88     static int n,m,lastans,ope;
 89     static char o[20];
 90     n = getint() , m = getint();
 91     for(int i=0,x;i<n;i++) x = getint() , dat[0].insert(i,x);
 92     for(int i=1,p,x,t;i<=m;i++) {
 93         getstr(o);
 94         if( *o == 'Q' ) {
 95             p = ( getint() ^ lastans ) % n;
 96             printint(lastans=query(p));
 97         } else if( *o == 'M' ) {
 98             ++ope , p = ( getint() ^ lastans ) % n , x = getint();
 99             modify(p,x);
100         } else if( *o == 'R' ) {
101             ++ope , t = ( getint() ^ lastans ) % ope;
102             roll(t);
103         }
104     }
105     flush();
106     return 0;
107 }
View Code

 


T3:


大力反演出phi,后面的sigma(i^k)显然是k+1次多项式,拉格朗日插值即可。
代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define debug cout
  6 #define bool unsigned char
  7 typedef long long int lli;
  8 using namespace std;
  9 const int maxn=1e6+1e2,lim=1e6,maxk=1e3+1e1;
 10 const int mod=1e9+7;
 11 
 12 int n,k;
 13 
 14 namespace Sieve {
 15     lli sum[maxn],mem[maxn];
 16     bool vis[maxn];
 17     
 18     inline void pre() {
 19         static int prime[maxn/10],cnt;
 20         static bool vis[maxn];
 21         sum[1] = 1;
 22         for(int i=2;i<=lim;i++) {
 23             if( !vis[i] ) prime[++cnt] = i , sum[i] = i - 1;
 24             for(int j=1;j<=cnt&&(lli)i*prime[j]<=lim;j++) {
 25                 const int tar = i * prime[j];
 26                 vis[tar] = 1;
 27                 if( i % prime[j] ) sum[tar] = sum[i] * ( prime[j] - 1 );
 28                 else {
 29                     sum[tar] = sum[i] * prime[j];
 30                     break;
 31                 }
 32             }
 33         }
 34         for(int i=1;i<=lim;i++) sum[i] = ( sum[i] + sum[i-1] ) % mod;
 35     }
 36     inline lli getphi(lli x) {
 37         if( x <= lim ) return sum[x];
 38         const lli t = n / x;
 39         if( vis[t] ) return mem[t];
 40         lli& ret = mem[t]; ret = x * ( x + 1 ) >> 1  , vis[t] = 1;
 41         for(lli i=2,j;i<=x;i=j+1) {
 42             j = x / ( x / i );
 43             ret -= ( j - i + 1 ) * getphi(x/i) % mod , ret %= mod;
 44         }
 45         return ret = ( ret % mod + mod ) % mod;
 46     }
 47 }
 48 
 49 namespace Inter {
 50     lli in[maxk],fac[maxk],facrev[maxk],pprv[maxk],ssuf[maxk],*prv=pprv+1,*suf=ssuf+1;
 51     inline lli fastpow(lli base,int tim) {
 52         lli ret = 1;
 53         while(tim) {
 54             if( tim & 1 ) ret = ret * base % mod;
 55             if( tim >>= 1 ) base = base * base % mod;
 56         }
 57         return ret;
 58     }
 59     inline void init() {
 60         for(int i=1;i<k;i++) in[i] = fastpow(i,k-2);
 61         for(int i=1;i<k;i++) in[i] = ( in[i] + in[i-1] ) % mod;
 62     }
 63     inline lli getmul(int p) {
 64         return p ? fac[p] * facrev[k-p-1] % mod : facrev[k-1];
 65     }
 66     inline lli getval(lli x) {
 67         lli ret = 0;
 68         prv[-1] = 1;
 69         for(int i=0;i<k;i++) prv[i] = prv[i-1] * (x-i+mod) % mod;
 70         suf[k] = 1;
 71         for(int i=k-1;~i;i--) suf[i] = suf[i+1] * (x-i+mod) % mod;
 72         for(int i=0;i<k;i++) {
 73             lli now = prv[i-1] * suf[i+1] % mod;
 74             ret = ret + now * in[i] % mod * getmul(i) % mod , ret %= mod;
 75         }
 76         return ret;
 77     }
 78     inline void getinv() {
 79         static lli inv[maxn];
 80         *fac = 1;
 81         for(int i=1;i<=k;i++) fac[i] = fac[i-1] * i % mod;
 82         inv[k] = fastpow(fac[k],mod-2);
 83         for(int i=k;i;i--) inv[i-1] = inv[i] * i % mod;
 84         for(int i=1;i<=k;i++) inv[i] = inv[i] * fac[i-1] % mod;
 85         for(int i=1;i<=k;i++) fac[i] = fac[i-1] * inv[i] % mod;
 86         facrev[0] = 1;
 87         for(int i=1;i<=k;i++) facrev[i] = facrev[i-1] * ( mod - inv[i] ) % mod;
 88     }
 89 }
 90 inline lli segphi(lli l,lli r) {
 91     return ( Sieve::getphi(r) - Sieve::getphi(l-1) + mod ) % mod;
 92 }
 93 
 94 inline lli calc(lli n) {
 95     lli ret = 0;
 96     for(lli i=1,j;i<=n;i=j+1) {
 97         j = n / ( n / i );
 98         ret += segphi(i,j) % mod * Inter::getval(n/i) % mod , ret %= mod;
 99     }
100     return ret;
101 }
102 
103 int main() {
104     scanf("%d%d",&n,&k) , k += 2 , Sieve::pre() , Inter::init() , Inter::getinv();
105     printf("%lld\n",calc(n));
106     return 0;
107 }
View Code

 

 

当然那个RYOI是什么意思?就不告诉你!

 

转载于:https://www.cnblogs.com/Cmd2001/p/8698088.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值