北京集训:20180318
果然我还是太菜了......
T1:
先分解成标准形式,然后每个质因数必须有最高次,然后状压DP?
发现并不可做......
然后写了10分的大力背包走了......
正解是容斥。
然而他的公式挂了......
大概意思就是枚举我们有几个没有到最高次,然后用高维前缀和(积)进行DP。
关于高维前缀和可以看我以前的博客......
为什么考场没想起来......
考场10分代码:
1 #include<cstdio> 2 #include<cstring> 3 //#include<iostream> 4 //#define debug cout 5 //using namespace std; 6 typedef long long int lli; 7 const int maxn=5e2+1e1,maxk=22; 8 const int mod=232792561; 9 10 lli f[2][maxn][maxk]; 11 int n,k; 12 13 inline int gcd(int x,int y) { 14 register int t; 15 while( t = x % y ) 16 x = y , y = t; 17 return y; 18 } 19 inline int lcm(int x,int y) { 20 if( ! ( x && y ) ) return x | y; 21 return x / gcd(x,y) * y; 22 } 23 inline void trans(lli dst[maxn][maxk],const lli sou[maxn][maxk],int now) { 24 for(int i=0;i<=n;i++) { 25 const int tar = lcm(i,now); 26 if( tar > n ) continue; 27 for(int j=0;j<k;j++) ( dst[tar][(j+now)%k] += sou[i][j] ) %= mod; 28 } 29 for(int i=0;i<=n;i++) 30 for(int j=0;j<k;j++) 31 ( dst[i][j] += sou[i][j] ) %= mod; 32 } 33 34 int main() { 35 static int T,cur; 36 scanf("%d",&T); 37 while(T--) { 38 memset(f,0,sizeof(f)) , cur = 0; 39 f[cur][0][0] = 1; 40 scanf("%d%d",&n,&k); 41 for(int i=1;i<=n;i++) { 42 cur ^= 1; 43 memset(f[cur],0,sizeof(f[1])); 44 trans(f[cur],f[cur^1],i); 45 } 46 printf("%lld\n",f[cur][n][0]); 47 } 48 return 0; 49 }
正解代码:
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 maxl=2e5+1e2,maxd=2e1+1e1,maxp=7e1+1e1; 9 const int mod=232792561; 10 11 int k; 12 lli wpows[maxd]; 13 14 inline lli fastpow(lli base,int tim) { 15 lli ret = 1; 16 while( tim ) { 17 if( tim & 1 ) ret = ret * base % mod; 18 if( tim >>= 1 ) base = base * base % mod; 19 } 20 return ret; 21 } 22 23 struct Poly { 24 lli dat[maxd]; 25 Poly() { 26 memset(dat,0,sizeof(dat)); 27 } 28 inline void fill(int x) { // get point value expression , only p ^ x and p ^ 0 is 1 . 29 for(int i=0;i<k;i++) 30 dat[i] = ( wpows[x*i%k] + 1 ) % mod; 31 } 32 friend Poly operator + (const Poly &a,const Poly &b) { 33 Poly ret; 34 for(int i=0;i<k;i++) ret.dat[i] = ( a.dat[i] + b.dat[i] ) % mod; 35 return ret; 36 } 37 friend Poly operator - (const Poly &a,const Poly &b) { 38 Poly ret; 39 for(int i=0;i<k;i++) ret.dat[i] = ( a.dat[i] - b.dat[i] + mod ) % mod; 40 return ret; 41 } 42 friend Poly operator * (const Poly &a,const Poly &b) { 43 Poly ret; 44 for(int i=0;i<k;i++) ret.dat[i] = a.dat[i] * b.dat[i] % mod; 45 return ret; 46 } 47 inline lli calc() { 48 lli ret = 0; 49 for(int i=0;i<k;i++) ( ret += dat[i] ) %= mod; 50 ret = ret * fastpow(k,mod-2) % mod; 51 return ret; 52 } 53 }f[maxl]; 54 55 lli dvs[maxd],dvspows[maxd][maxp]; 56 int tim[maxd],facs[maxd]; 57 int cnt,full; 58 59 inline void prew() { 60 const lli w = fastpow(71,mod/k); 61 *wpows = 1; 62 for(int i=1;i<k;i++) wpows[i] = wpows[i-1] * w % mod; 63 } 64 inline void cut(lli x) { 65 for(int i=2;i<=100;i++) 66 if( ! ( x % i ) ) { 67 dvs[++cnt] = i , dvspows[cnt][0] = 1; 68 while( ! ( x % i ) ) { 69 ++tim[cnt] , 70 dvspows[cnt][tim[cnt]] = dvspows[cnt][tim[cnt]-1] * i , 71 x /= i; 72 } 73 } 74 } 75 inline void getfac() { 76 *facs = 1; 77 for(int i=1;i<=cnt;i++) facs[i] = facs[i-1] * ( tim[i] + 1 ); 78 } 79 inline lli getnum(int id) { // access as high-dimension array . 80 lli ret = 1; 81 for(int i=1;i<=cnt;i++) ret *= dvspows[i][id%facs[i]/facs[i-1]]; 82 return ret; 83 } 84 inline void dp() { 85 for(int j=1;j<=cnt;j++) 86 for(int i=0;i<full;i++) 87 if( i % facs[j] / facs[j-1] ) 88 f[i] = f[i] * f[i-facs[j-1]]; 89 } 90 inline Poly getans() { 91 Poly ret; 92 for(int sta=0;sta<(1<<cnt);sta++) { 93 int sg = 1 , now = full - 1; 94 for(int i=1;i<=cnt;i++) if( sta & ( 1 << ( i - 1 ) ) ) { 95 sg *= -1 , now -= facs[i-1]; 96 } 97 if( sg == 1 ) ret = ret + f[now]; 98 else ret = ret - f[now]; 99 } 100 return ret; 101 } 102 inline void init() { 103 memset(tim,0,sizeof(tim)) , cnt = 0; 104 memset(f,0,sizeof(f)); 105 } 106 107 int main() { 108 static int T; 109 static lli n; 110 scanf("%d",&T); 111 while(T--) { 112 scanf("%lld%d",&n,&k) , init() , prew(); 113 cut(n) , getfac() , full = facs[cnt]; 114 for(int i=0;i<full;i++) { 115 lli now = getnum(i); 116 f[i].fill(now%k); 117 } 118 dp(); 119 Poly ans = getans(); 120 printf("%lld\n",ans.calc()); 121 } 122 return 0; 123 }
T2:
显然是个反演+杜教筛......
三个gcd很不好办啊,拆了他也不好做,不如留着,万一大力出奇迹了呢......
前面是μ*id=φ,后面是x^2的前缀和,显然可以背过......
话说考场如果背不过怎么办呢?显然他是一个k+1次多项式,然后我们可以拉格朗日插值......
官方题解感觉推傻了......
考场AC代码:
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=1e6+1e2,lim=1e6; 9 10 lli phi[maxn],mem[maxn],vis[maxn]; 11 int n,mod,inv; 12 13 inline lli fastpow(lli base,int tim) { 14 lli ret = 1; 15 while( tim ) { 16 if( tim & 1 ) ret = ret * base % mod; 17 if( tim >>= 1 ) base = base * base % mod; 18 } 19 return ret; 20 } 21 22 inline void sieve() { 23 static int vis[maxn],prime[maxn],cnt; 24 phi[1] = 1; 25 for(int i=2;i<=lim;i++) { 26 if( !vis[i] ) prime[++cnt] = i , phi[i] = i - 1; 27 for(int j=1;j<=cnt&&(lli)i*prime[j]<=lim;j++) { 28 const int tar = i * prime[j]; 29 vis[tar] = 1; 30 if( i % prime[j] ) phi[tar] = phi[i] * ( prime[j] - 1 ); 31 else { 32 phi[tar] = phi[i] * prime[j]; 33 break; 34 } 35 } 36 } 37 for(int i=1;i<=lim;i++) ( phi[i] += phi[i-1] ) %= mod; 38 } 39 40 inline lli sumphi(lli x) { 41 if( x <= lim ) 42 return phi[x]; 43 lli mp = n / x; 44 if( vis[mp] ) 45 return mem[mp]; 46 lli ret = ( (lli) x ) * ( x + 1 ) >> 1; 47 for(lli i=2,j;i<=x;i=j+1) { 48 j = x / ( x / i ); 49 ret -= ( j - i + 1 ) * sumphi( x / i ); 50 } 51 vis[mp] = 1; 52 return mem[mp] = ret; 53 } 54 55 inline lli sum(lli x) { 56 return x * ( x + 1 ) % mod * ( ( 2 * x + 1 ) % mod ) % mod * inv % mod; 57 } 58 inline lli segphi(lli l,lli r) { 59 return ( sumphi(r) - sumphi(l-1) + mod ) % mod; 60 } 61 inline lli calc(lli n) { 62 lli ret = 0; 63 for(lli i=1,j;i<=n;i=j+1) { 64 j = n / ( n / i ); 65 ( ret += segphi(i,j) * sum( n / i ) % mod ) %= mod; 66 } 67 return ret; 68 } 69 70 int main() { 71 scanf("%d%d",&n,&mod) , sieve(); 72 inv = fastpow(6,mod-2); 73 printf("%lld\n",calc(n)); 74 return 0; 75 }
T3:
字符串题,没时间了,写个20分暴力走了。
woc暴力怎么又WA了?
题解:
考场零分暴力:
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 const int maxn=1e2+1e1,maxq=1e5+1e2; 10 11 struct ACautomatic { 12 int ch[maxn][26],fail[maxn],deg[maxn],sum[maxn],tim[maxn],root,cnt; 13 ACautomatic() { root = ++cnt; } 14 inline void insert(char* s,int li) { 15 int now = root; 16 for(int i=1;i<=li;i++) { 17 const int t = s[i] - 'a'; 18 if( !ch[now][t] ) ch[now][t] = ++cnt; 19 now = ch[now][t]; 20 } 21 //debug<<"now = "<<now<<endl; 22 ++sum[now]; 23 } 24 inline void buildfail() { 25 std::queue<int> q; 26 for(int i=0;i<26;i++) 27 if( !ch[root][i] ) ch[root][i] = i; 28 else fail[ch[root][i]] = root , q.push(ch[root][i]); 29 while( q.size() ) { 30 const int pos = q.front(); q.pop(); 31 for(int i=0;i<26;i++) 32 if( !ch[pos][i] ) ch[pos][i] = ch[fail[pos]][i]; 33 else fail[ch[pos][i]] = ch[fail[pos]][i] , q.push(ch[pos][i]); 34 } 35 } 36 inline void pir(char* s,int li) { 37 int now = root; 38 for(int i=0;i<li;i++) { 39 const int t = s[i] - 'a'; 40 //debug<<"now = "<<now<<endl; 41 now = ch[now][t] , ++tim[now]; 42 } 43 } 44 inline lli calc() { 45 lli ret = 0; 46 std::queue<int> q; 47 for(int i=1;i<=cnt;i++) if( fail[i] ) ++deg[fail[i]]; 48 for(int i=1;i<=cnt;i++) if( !deg[i] ) q.push(i); 49 while( q.size() ) { 50 const int pos = q.front(); q.pop(); 51 if( pos == root ) continue; 52 ret += (lli) tim[pos] * sum[pos]; 53 tim[fail[pos]] += tim[pos]; 54 if( !--deg[fail[pos]] ) q.push(fail[pos]); 55 } 56 return ret; 57 } 58 inline void rtq() { 59 memset(deg,0,sizeof(deg)) , memset(tim,0,sizeof(tim)); 60 } 61 }AC; 62 63 char in[maxq],tp[maxq]; 64 65 int main() { 66 static int n,q,li; 67 scanf("%d%d",&n,&q); 68 for(int i=1;i<=n;i++) { 69 scanf("%s",tp+1) , li = strlen(tp+1); 70 AC.insert(tp,li); 71 } 72 AC.buildfail(); 73 scanf("%s",in+1); 74 for(int i=1,o,l,r;i<=q;i++) { 75 scanf("%d%d%d",&o,&l,&r); 76 if( o == 2 ) { 77 AC.rtq(); 78 AC.pir(in+l,r-l+1); 79 printf("%lld\n",AC.calc()); 80 } else { 81 scanf("%s",tp) , li = strlen(tp); 82 for(int j=0;j<r-l+1;j++) 83 in[l+j] = tp[j%li]; 84 } 85 } 86 return 0; 87 }
标程:
1 #include<bits/stdc++.h> 2 #define ALPHA 27 3 #define N 55 4 #define M 100005 5 #define pii pair<int,int> 6 #define mp(x,y) make_pair(x,y) 7 #define fr first 8 #define se second 9 using namespace std; 10 namespace AC{ 11 int ne[M][ALPHA],fail[M],val[M],cnt,root;//0~cnt-1 12 void insert(int &k,char *s,int len){ 13 if(k==0) k=++cnt; 14 if(len!=0) insert(ne[k][s[0]-'a'],s+1,len-1); 15 else val[k]++; 16 } 17 void buildAC(){ 18 fail[root]=root;queue<int> q; 19 for(int i=0;i<26;i++) 20 if(ne[root][i]==0) ne[root][i]=root; 21 else fail[ne[root][i]]=root,q.push(ne[root][i]); 22 while(!q.empty()){ 23 int u=q.front();q.pop(); 24 for(int i=0;i<26;i++){ 25 int &v=ne[u][i]; 26 if(v==0) v=ne[fail[u]][i]; 27 else fail[v]=ne[fail[u]][i],q.push(v),val[v]+=val[fail[v]]; 28 } 29 } 30 } 31 } 32 33 struct msg{ 34 int st[N],ans[N]; 35 pii query(pii x){ 36 return mp(st[x.fr],x.se+ans[x.fr]); 37 } 38 void merge(const msg &b){ 39 for(int i=0;i<AC::cnt;i++) ans[i]+=b.ans[st[i]],st[i]=b.st[st[i]]; 40 } 41 void ini(){ 42 for(int i=0;i<AC::cnt;i++) st[i]=i,ans[i]=0; 43 } 44 void inital(char ch){ 45 for(int i=0;i<AC::cnt;i++) st[i]=AC::ne[i+1][ch-'a']-1,ans[i]=AC::val[st[i]+1]; 46 } 47 }; 48 msg ne[M*19]; 49 #define gid(pos,pw) ((pos)*18+(pw)) 50 char str[M];int len,lenth[M],li[M],ri[M],idcnt; 51 void prework(int l,int r,int d){ 52 int mlen=(r-l+1); 53 for(int i=l;i<=r;i++) ne[gid(i,0)].inital(str[i]); 54 for(int i=1;(1<<i)<=d;i++) 55 for(int j=l;j<=r;j++) 56 ne[gid(j,i)]=ne[gid(j,i-1)],ne[gid(j,i)].merge(ne[gid((j-l+(1<<(i-1)))%mlen+l,i-1)]); 57 } 58 59 namespace SGT{ 60 struct xds{ 61 int pw; 62 msg x; 63 int tagid,pos; 64 }a[(1<<18)+3];int cnt; 65 inline void addmark(int k,int id,int pos){ 66 a[k].x=ne[gid(li[id]+pos,a[k].pw)]; 67 a[k].tagid=id;a[k].pos=pos; 68 } 69 inline void pushdown(int k){ 70 if(a[k].tagid==0||a[k].pw==0) return; 71 addmark(k<<1,a[k].tagid,a[k].pos); 72 int npos=(a[k].pos+(1<<(a[k].pw-1)))%lenth[a[k].tagid]; 73 addmark(k<<1|1,a[k].tagid,npos); 74 a[k].tagid=0;a[k].pos=0; 75 } 76 inline void update(int k){ 77 a[k].x=a[k<<1].x; 78 a[k].x.merge(a[k<<1|1].x); 79 } 80 void build(int k,int l,int r,char *s,int pw){ 81 a[k].pw=pw; 82 if(l==r){ 83 a[k].x.inital(s[l]);return; 84 }else{ 85 int mid=(l+r)>>1; 86 build(k<<1,l,mid,s,pw-1); 87 build(k<<1|1,mid+1,r,s,pw-1); 88 update(k); 89 } 90 } 91 pii query(int k,int l,int r,pii input,int nl,int nr){ 92 if(nl==l&&nr==r) return a[k].x.query(input); 93 pushdown(k); 94 int mid=(nl+nr)>>1; 95 if(l>mid) return query(k<<1|1,l,r,input,mid+1,nr); 96 else if(r<=mid) return query(k<<1,l,r,input,nl,mid); 97 return query(k<<1|1,mid+1,r,query(k<<1,l,mid,input,nl,mid),mid+1,nr); 98 } 99 void modify(int k,int l,int r,int id,int st,int nl,int nr){ 100 if(nl==l&&nr==r){ 101 addmark(k,id,st); 102 }else{ 103 pushdown(k); 104 int mid=(nl+nr)>>1; 105 if(l>mid) modify(k<<1|1,l,r,id,st,mid+1,nr); 106 else if(r<=mid) modify(k<<1,l,r,id,st,nl,mid); 107 else modify(k<<1,l,mid,id,st,nl,mid),modify(k<<1|1,mid+1,r,id,(st+mid-l+1)%lenth[id],mid+1,nr); 108 update(k); 109 } 110 } 111 } 112 113 char s[(1<<18)+3],Ti[N]; 114 int n,m,q,pwlen; 115 void readin(){ 116 //cerr<<(sizeof(ne)+sizeof(SGT::a))/1024/1024<<endl; 117 memset(s,'a',sizeof(s)); 118 scanf("%d%d",&n,&q); 119 for(int i=1;i<=n;i++) scanf("%s",Ti),AC::insert(AC::root,Ti,strlen(Ti)); 120 scanf("%s",s+1); 121 m=strlen(s+1); 122 s[m+1]='a'; 123 } 124 void solve(){ 125 for(int i=1;i<=q;i++){ 126 int op,l,r; 127 scanf("%d%d%d",&op,&l,&r); 128 if(op==1){ 129 scanf("%s",str+len);idcnt++; 130 li[idcnt]=len;len+=strlen(str+len);ri[idcnt]=len-1; 131 lenth[idcnt]=ri[idcnt]-li[idcnt]+1; 132 prework(li[idcnt],ri[idcnt],r-l+1); 133 SGT::modify(1,l,r,idcnt,0,1,(1<<pwlen)); 134 }else{ 135 pii ret=mp(0,0); 136 ret=SGT::query(1,l,r,ret,1,(1<<pwlen)); 137 printf("%d\n",ret.se); 138 } 139 } 140 if(len>100000) {puts("Invaid Input2");return;} 141 } 142 int main(){ 143 144 readin(); 145 AC::buildAC(); 146 if(AC::cnt>50) return puts("Invaid Input1"),0; 147 for(pwlen=0;(1<<pwlen)<m;pwlen++); 148 SGT::build(1,1,(1<<pwlen),s,pwlen); 149 solve(); 150 return 0; 151 }