https://konnyakuxzy.github.io/BZPRO/JudgeOnline/4059.html
https://cn.vjudge.net/problem/Gym-100624D
根本不会。。。
似乎有很高妙的分治做法啊!https://www.cnblogs.com/forever97/p/bzoj4059.html
就是说,如果当前区间为[l,r],存在一个i满足pre[i]<l&&nxt[i]>r,那么任意一个[l,r]的子区间,只要包含i点就不无聊,因此只需要再检验[l,i-1]和[i+1,r]即可
复杂度n*log就是因为倒过来就是启发式合并的过程。。。
以前代码很奇怪不知道怎么回事也A掉了。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
if(i==j) break; i++; if(pre[i]<l&&nxt[i]>r) return solve(l,i-1)&&solve(i+1,r); if(i==j) break; j--; if(pre[j]<l&&nxt[j]>r) return solve(l,j-1)&&solve(j+1,r);
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 #include<map> 6 using namespace std; 7 #define fi first 8 #define se second 9 #define mp make_pair 10 #define pb push_back 11 typedef long long ll; 12 typedef unsigned long long ull; 13 typedef pair<int,int> pii; 14 int n,T,a[200100]; 15 int pre[200100],nxt[200100]; 16 map<int,int> ma; 17 bool solve(int l,int r) 18 { 19 if(l>=r) return 1; 20 int i,j; 21 for(i=l,j=r;;) 22 { 23 if(pre[i]<l&&nxt[i]>r) return solve(l,i-1)&&solve(i+1,r); 24 i++; 25 if(i>j) break; 26 if(pre[j]<l&&nxt[j]>r) return solve(l,j-1)&&solve(j+1,r); 27 j--; 28 if(i>j) break; 29 } 30 return 0; 31 } 32 int main() 33 { 34 int i; 35 scanf("%d",&T); 36 while(T--) 37 { 38 scanf("%d",&n); 39 for(i=1;i<=n;i++) scanf("%d",&a[i]); 40 ma.clear(); 41 for(i=1;i<=n;i++) 42 { 43 pre[i]=ma.count(a[i])?ma[a[i]]:0; 44 ma[a[i]]=i; 45 } 46 ma.clear(); 47 for(i=n;i>=1;i--) 48 { 49 nxt[i]=ma.count(a[i])?ma[a[i]]:n+1; 50 ma[a[i]]=i; 51 } 52 puts(solve(1,n)?"non-boring":"boring"); 53 } 54 return 0; 55 }
也有很高妙的扫描线做法啊!https://blog.csdn.net/PoPoQQQ/article/details/46380617
https://konnyakuxzy.github.io/BZPRO/JudgeOnline/5200.html
https://cn.vjudge.net/problem/Gym-101623F
做法跟上面那题几乎是一样的
仍然不会。。。
做法是类似的,卡在”区间内有多个可作为根的位置时,如何选择“上了
上网查了一下,发现怎样选择并不会影响答案。。。
证明很简单:假设已经得到了区间内一组以a为根的合法解,b也是一个合法根,直接把这棵树的根改为b,那么显然只有a到b的链上的所有边的两个端点的父亲-祖先关系反了一下,显然这条链上端点的值两两互质,因此这样子换根之后也是合法解
还有一点:我自己想的是每次分治直接分解质因数然后怎么怎么样,很慢,可能被卡常(质因数分解n^(1/4)吧?)
然而,可以直接线筛出1e7内每个数的最小质因子。。。然后分解质因子复杂度只要一个log
而且,只需要预处理每个数的上一个和下一个与其不互质的数位置即可。。。感觉常数要小不少啊
错误记录:
1.已经发现了需要单独记录f[t],然后while才能除以的是同一个数(就是需要69行),但是只改了一半(没改81行)
2.LA上有多组数据,但是我没有完整地清空(WA了很多发,包括61行,87行(需要fa[..]=0))
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 #include<map> 6 using namespace std; 7 #define fi first 8 #define se second 9 #define mp make_pair 10 #define pb push_back 11 typedef long long ll; 12 typedef unsigned long long ull; 13 typedef pair<int,int> pii; 14 bool nprime[10000010]; 15 int prime[1000100],len,f[10000010]; 16 int n,a[1001000]; 17 int pre[1001000],nxt[1001000]; 18 map<int,int> ma; 19 bool fl; 20 int fa[1001000]; 21 int solve(int l,int r) 22 { 23 if(l>r) return 0; 24 if(l==r) return l; 25 int i,j; 26 for(i=l,j=r;;) 27 { 28 if(pre[i]<l&&nxt[i]>r) 29 { 30 fa[solve(l,i-1)]=i; 31 fa[solve(i+1,r)]=i; 32 return i; 33 } 34 i++; 35 if(i>j) break; 36 if(pre[j]<l&&nxt[j]>r) 37 { 38 fa[solve(l,j-1)]=j; 39 fa[solve(j+1,r)]=j; 40 return j; 41 } 42 j--; 43 if(i>j) break; 44 } 45 fl=1; 46 return 0; 47 } 48 int main() 49 { 50 int i,j,t,q; 51 for(i=2;i<=10000000;i++) 52 { 53 if(!nprime[i]) prime[++len]=i,f[i]=i; 54 for(j=1;j<=len&&i*prime[j]<=10000000;j++) 55 { 56 nprime[i*prime[j]]=1;f[i*prime[j]]=prime[j]; 57 if(i%prime[j]==0) break; 58 } 59 } 60 while(scanf("%d",&n)==1){ 61 fl=0; 62 for(i=1;i<=n;i++) scanf("%d",&a[i]); 63 ma.clear(); 64 for(i=1;i<=n;i++) 65 { 66 t=a[i];pre[i]=0; 67 while(t!=1) 68 { 69 q=f[t]; 70 pre[i]=max(pre[i],ma.count(q)?ma[q]:0); 71 ma[q]=i; 72 while(t%q==0) t/=q; 73 } 74 } 75 ma.clear(); 76 for(i=n;i>=1;i--) 77 { 78 t=a[i];nxt[i]=n+1; 79 while(t!=1) 80 { 81 q=f[t]; 82 nxt[i]=min(nxt[i],ma.count(q)?ma[q]:n+1); 83 ma[q]=i; 84 while(t%q==0) t/=q; 85 } 86 } 87 fa[solve(1,n)]=0; 88 if(fl) puts("impossible"); 89 else 90 { 91 for(i=1;i<=n;i++) 92 { 93 printf("%d",fa[i]); 94 if(i!=n) putchar(' '); 95 } 96 puts(""); 97 }} 98 return 0; 99 }