20180507小測
對我而言相當失敗的一次考試呢。
(昨天失了智一晚上沒睡覺還好意思說)
T1:
看到數據範圍與值域有關,是不是想到了一些有趣的事情呢?
兩兩gcd為1,顯然我們把同時選出的數分解質因子後,每個質數出現最多一次。是不是能狀壓DP呢?
(然後我發現2000內的質數有將近200個,沒法狀壓,然後寫了30分暴力)
這裏有一個很顯然的性質,數字x>=sqrt(x)的質因子最多只有1個,所以我們只需要狀壓<=sqrt(2000)的質因數,即{2-43},只有14個。
其余的,我們能按照大質因子分組,然後每組最多選1個數字。
我們令f[i][sta]表示前i組,質因數狀態為sta的方案數。轉移的話可以枚舉這組選擇哪個數字,然後進行轉移。
註意沒有>43質因子的數字要各自一組,因為它們不存在互斥狀態。
代碼:
1 #include<cstdio> 2 #include<algorithm> 3 #include<vector> 4 typedef long long int lli; 5 const int maxn=2e3+1e2,maxs=(1<<14)+5; 6 const int prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43},pl=14,full=1<<14; 7 const int mod=1e9+7; 8 9 struct Node { 10 intView Codesta,mx; 11 friend bool operator < (const Node &a,const Node &b) { return a.mx > b.mx; } 12 }ns[maxn]; 13 14 std::vector<Node> grp[maxn]; 15 lli f[maxn][maxs],ans; 16 int n,cnt; 17 18 inline Node cut(int x) { 19 int ret = 0; 20 for(int i=0;i<pl;i++) 21 if( ! ( x % prime[i] ) ) {22 ret |= (1<<i); 23 while( ! ( x % prime[i] ) ) x /= prime[i]; 24 } 25 return (Node){ret,x}; 26 } 27 28 inline void getgrp() { 29 std::sort(ns+1,ns+1+n); 30 for(int i=1;i<=n;i++) { 31 if( ns[i].mx != ns[i-1].mx || ns[i].mx == 1 ) ++cnt; 32 grp[cnt].push_back(ns[i]); 33 } 34 } 35 inline void dp() { 36 **f = 1; 37 for(int i=1;i<=cnt;i++) { 38 for(unsigned cur=0;cur<grp[i].size();cur++) 39 for(int sta=0;sta<full;sta++) { 40 if( ! ( sta & grp[i][cur].sta ) ) 41 f[i][sta|grp[i][cur].sta] = ( f[i][sta|grp[i][cur].sta] + f[i-1][sta] ) % mod; 42 } 43 for(int sta=0;sta<full;sta++) f[i][sta] = ( f[i][sta] + f[i-1][sta] ) % mod; 44 } 45 for(int i=0;i<full;i++) ans = ( ans + f[cnt][i] ) % mod; 46 } 47 48 int main() { 49 scanf("%d",&n); 50 for(int i=1,t;i<=n;i++) scanf("%d",&t) , ns[i] = cut(t); 51 getgrp() , dp() , printf("%lld\n",(ans-1+mod)%mod); 52 return 0; 53 }
T2:
字符串題,我只會後綴自動機......
很好,這題,後綴自動機不可做......然後我就GG了。
考慮SAM怎麽做這道題,我們用可持久話線段樹記錄每個點的right集合,然後我們要找<=節點len的right集合中兩個數的最大差......
這個東西由於存在自身對自身的貢獻,所以沒法啟發式合並。
然後我就寫了48分哈希。
考慮用後綴數組求LCP和LCS。
我們考慮枚舉這個串的循環節的一半為i,然後在這個字符串中取1+k*i位置為關鍵點。
然後枚舉兩個相鄰的關鍵點。顯然如果有一個能滿足條件的串存在的話,它一定是前一半過第一個關鍵點,後一半過第二個關鍵點的。
好的,我們可以求出這兩個點的LCP和LCS之和,如果>=i的話,則證明存在長度>=i的滿足條件的串。
復雜度為O(nlogn),註意構造後綴數組不能用SAM,會MLE.....要麽DC3或者後綴平衡樹,要麽老老實實寫倍增(然而我不會倍增)。
爆內存的SAM:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define debug cout 6 using namespace std; 7 const int maxn=2e6+1e2,maxl=23; 8 9 char in[maxn>>1]; 10 int Log[maxn>>1],li,ans; 11 12 struct SuffixAutomatic { 13 int ch[maxn][26],tc[maxn][26],fa[maxn],len[maxn],rit[maxn],root,last,cnt; 14 int stk[maxn],sa[maxn>>1],rnk[maxn>>1],h[maxn>>1],rmq[maxn>>1][maxl],top,sal; 15 SuffixAutomatic() { last = root = cnt = 1; } 16 inline int NewNode(int ll) { 17 return len[++cnt] = ll , cnt; 18 } 19 inline void extend(int x,int r) { 20 int p = last , np = NewNode(len[p]+1); rit[np] = r; 21 while( p && !ch[p][x] ) ch[p][x] = np , p = fa[p]; 22 if( !p ) fa[np] = root; 23 else { 24 int q = ch[p][x]; 25 if( len[q] == len[p] + 1 ) fa[np] = q; 26 else { 27 int nq = NewNode(len[p]+1); 28 memcpy(ch[nq],ch[q],sizeof(ch[q])) , fa[nq] = fa[q] , fa[np] = fa[q] = nq; 29 while( p && ch[p][x] == q ) ch[p][x] = nq , p = fa[p]; 30 } 31 } 32 last = np; 33 } 34 inline void pre(int pos) { 35 for(int i=0,t;i<26;i++) if( ( t = ch[pos][i] ) && len[t] == len[pos] + 1 ) { 36 stk[++top] = i , tc[fa[t]][stk[len[t]-len[fa[t]]]] = t , pre(t) , stk[top--] = ‘\0‘; 37 } 38 } 39 inline void dfs(int pos) { 40 if( rit[pos] ) sa[++sal] = rit[pos]; 41 for(int i=0;i<26;i++) if( tc[pos][i] ) dfs(tc[pos][i]); 42 } 43 inline void geth(char* in,int li) { 44 for(int i=1;i<=sal;i++) rnk[sa[i]] = i; 45 reverse(in+1,in+1+li); 46 for(int i=1,k=0;i<=sal;i++) { 47 k -= (bool)k; 48 const int p = sa[rnk[i]-1]; 49 while( in[i+k] == in[p+k] ) ++k; 50 h[rnk[i]-1] = k; 51 } 52 reverse(in+1,in+1+li); 53 } 54 inline void initrmq() { 55 for(int i=1;i<sal;i++) rmq[i][0] = h[i]; 56 for(int j=1;j<=Log[sal];j++) for(int i=1;i<sal;i++) rmq[i][j] = min( rmq[i][j-1] , rmq[i+(1<<(j-1))][j-1] ); 57 } 58 inline int query(int l,int r) { 59 l = rnk[l] , r = rnk[r]; 60 if( l > r ) swap(l,r); 61 --r; 62 int L = Log[r-l+1]; 63 return min( rmq[l][L] , rmq[r-(1<<L)+1][L] ); 64 } 65 inline void work(char* in,int li) { 66 for(int i=1;i<=li;i++) extend(in[i]-‘a‘,li-i+1); 67 pre(1) , dfs(1); 68 in[li+1] = ‘#‘ , geth(in,li) , initrmq(); 69 } 70 }prf,suf; 71 72 inline int lcp(int i,int j) { 73 return prf.query(i,j); 74 } 75 inline int lcs(int i,int j) { 76 return suf.query(li-j+1,li-i+1); 77 } 78 inline void calc(int len) { 79 for(int st=1,sst,lc;st+len<=li;st+=len) { 80 sst = st + len , lc = lcp(st,sst) + lcs(st-1,sst-1); 81 if( lc >= len ) { 82 ans = max( ans , len * 2 ); 83 } 84 } 85 } 86 87 int main() { 88 scanf("%s",in+1) , li = strlen(in+1); 89 for(int i=2;i<=li;i++) Log[i] = Log[i>>1] + 1; 90 suf.work(in,li) , reverse(in+1,in+1+li) , prf.work(in,li) , reverse(in+1,in+1+li); 91 for(int i=1;i<=li;i++) calc(i); 92 printf("%d\n",ans); 93 return 0; 94 }View Code
倍增:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define debug cout 6 using namespace std; 7 const int maxn=1e6+1e2,maxl=23; 8 9 char in[maxn>>1]; 10 int Log[maxn>>1],li,ans; 11 12 struct SuffixArray { 13 int sa[maxn],rnk[maxn],h[maxn],tax[maxn],tp[maxn],rmq[maxn][maxl],n,m; 14 inline void Resort() { 15 for(int i=0;i<=m;i++) tax[i] = 0; 16 for(int i=1;i<=n;i++) tax[rnk[i]]++; 17 for(int i=1;i<=m;i++) tax[i] += tax[i-1]; 18 for(int i=n;i;i--) sa[tax[rnk[tp[i]]]--] = tp[i]; 19 } 20 inline bool judge(int* s,int a,int b,int l) { 21 return s[a] == s[b] && s[a+l] == s[b+l]; 22 } 23 inline void buildh() { 24 for(int i=1,k=0,j;i<=n;i++) { 25 k = k ? k - 1 : 0 , j = sa[rnk[i]-1]; 26 while( in[i+k] == in[j+k] ) ++k; 27 h[rnk[i]-1] = k; 28 } 29 } 30 inline void get(char* in,int nn) { 31 n = nn; 32 for(int i=1;i<=n;i++) rnk[i] = in[i] , tp[i] = i; 33 m = 127 , Resort(); 34 for(int w=1,p=1;p<n;w+=w,m=p) { 35 p = 0; 36 for(int i=n-w+1;i<=n;i++) tp[++p] = i; 37 for(int i=1;i<=n;i++) if( sa[i] > w ) tp[++p] = sa[i] - w; 38 Resort(); swap(tp,rnk); rnk[sa[1]] = p = 1; 39 for(int i=2;i<=n;i++) 40 rnk[sa[i]] = judge(tp,sa[i],sa[i-1],w) ? p : ++p; 41 } 42 buildh() , initrmq(); 43 } 44 inline void initrmq() { 45 for(int i=1;i<n;i++) rmq[i][0] = h[i]; 46 for(int j=1;j<=Log[n];j++) for(int i=1;i<n;i++) rmq[i][j] = min( rmq[i][j-1] , rmq[i+(1<<(j-1))][j-1] ); 47 } 48 inline int query(int l,int r) { 49 l = rnk[l] , r = rnk[r]; 50 if( l > r ) swap(l,r); 51 --r; 52 int L = Log[r-l+1]; 53 return min( rmq[l][L] , rmq[r-(1<<L)+1][L] ); 54 } 55 }prf,suf; 56 57 inline int lcp(int i,int j) { 58 return prf.query(i,j); 59 } 60 inline int lcs(int i,int j) { 61 return suf.query(li-j+1,li-i+1); 62 } 63 inline void calc(int len) { 64 for(int st=1,sst,lc;st+len<=li;st+=len) { 65 sst = st + len , lc = lcp(st,sst) + lcs(st,sst); 66 if( lc >= len ) { 67 ans = max( ans , len * 2 ); 68 } 69 } 70 } 71 72 int main() { 73 scanf("%s",in+1) , li = strlen(in+1); 74 for(int i=2;i<=li;i++) Log[i] = Log[i>>1] + 1; 75 prf.get(in,li) , reverse(in+1,in+1+li) , suf.get(in,li); 76 for(int i=1;i<=li;i++) calc(i); 77 printf("%d\n",ans); 78 return 0; 79 }View Code
T3:
考試的時候根本沒時間看這題了(其實是前兩題不會就心態爆炸棄療了)。
正解是一個神奇的構造:
代碼:
1 #include<cstdio> 2 #include<algorithm> 3 const int maxn=2e5+1e2; 4 5 int a[maxn],b[maxn],sou[maxn],tar[maxn],swa[maxn][2],swb[maxn][2],n,al,bl; 6 7 int main() { 8 scanf("%d",&n); 9 for(int i=1;i<=n;i++) scanf("%d",a+i) , sou[a[i]] = i; 10 for(int i=1;i<=n;i++) scanf("%d",b+i) , tar[b[i]] = i; 11 for(int i=1,t;i<=n;i++) if( a[i] != b[i] ) { 12 if( tar[a[i]] >= sou[b[i]] ) std::swap(a[i],a[t=sou[b[i]]]) , sou[a[t]] = t , sou[a[i]] = i , swa[++al][0] = i , swa[al][1] = t; 13 else std::swap(b[i],b[t=tar[a[i]]]) , tar[b[t]] = t , tar[b[i]] = i , swb[++bl][0] = i , swb[bl][1] = t; 14 } 15 printf("%d\n",al+bl); 16 for(int i=1;i<=al;i++) printf("%d %d\n",swa[i][0],swa[i][1]); 17 for(int i=bl;i;i--) printf("%d %d\n",swb[i][0],swb[i][1]); 18 return 0; 19 }View Code
我は此処にて石となる 同胞を護る石となる
我願在此成為一塊石 成為保護兄弟姐妹的石頭
宜災いを受けてなお 物言わぬ石に在うべし
誠然地承受災難 一言不發的石頭
この災厄に觸れたとて 失うがこそ卑しけれ
以體驗這災禍為榮 以錯過此為恥
心より憎むものなれど 母の手に似た慰撫に泣く
雖然你從心裏憎恨我 但我會用如同母親般的手撫慰並為你流淚
我は此処にて石となる 幾千の時刻を越えた先
我願在此成為一塊石 成為歷經數千年的石頭
共に手をとり生きようと その顔を焼き付けて
在那臉上烙上[一起手牽手活下去吧]
呪われた血を今日は泣く 失うがこそ悲しいけれ
今天流下被詛咒的血淚 錯過了才是悲傷
愛し愛されたいと哭く 鬼の姿に人の夢
為想愛與被愛而哭 化身鬼魂現於人夢
20180507小測