北京集训: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 }
View Code

正解代码:

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


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


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

标程:

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

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值