2019-7-14 考试总结
A. 序列
首先,如果一个数列是等比数列并且公比$q!=1$的话,那么
- 对于它们中的每一个数,它都能被其他的任意一个数整除或者整除任意一个数。
- 并且他们不能互质,也就是$gcd!=1$。
- 不能有重复的数。
知道这个,这个题就基本上可以$AC$了,
理论复杂度基本上是$O(n^2)$,但是可以通过判断剪掉很多复杂度。
如果$q=1$,那么可以线性dp找最长重复序列。
如果$q!=1$,那么先枚举起点,再从起点往后枚举每个数,更新$ans$,
如果不满足那$3$个条件直接$break$。
丑陋的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<set> #define Maxn 1000050 #define Reg register using namespace std; const int L=1<<20|1; char buffer[L],*S,*TT; #define getchar() ((S==TT&&(TT=(S=buffer)+fread(buffer,1,L,stdin),S==TT))?EOF:*S++) long long n,maxx,num[Maxn],dp[Maxn],ans=1; inline long long max(long long x,long long y) {return x>y?x:y;} inline long long min(long long x,long long y) {return x<y?x:y;} inline long long read() { Reg long long a=0,b=1;Reg char ch=getchar(); while(ch<'0'||ch>'9') b=(ch=='-')?-1:1,ch=getchar(); while(ch>='0'&&ch<='9') a=(a<<3)+(a<<1)+(ch^48),ch=getchar(); return a*b; } inline long long gcd(Reg long long x,Reg long long y) { if(x==y) return x; else if(x==0||y==0) return x+y; else return gcd(y,x%y); } int main() { // freopen("text.in","r",stdin); n=read(); for(Reg int i=1;i<=n;++i) num[i]=read(); dp[1]=1; for(Reg int i=2;i<=n;++i) { if(num[i]==num[i-1]) dp[i]=dp[i-1]+1; else dp[i]=1; ans=max(ans,dp[i]); } for(Reg int i=1;i<=n-ans;++i) { Reg long long gcp; set<long long> q; q.clear(); Reg long long l1=max(num[i],num[i+1]); Reg long long l2=min(num[i],num[i+1]); if(l1%l2!=0) continue; gcp=l1/l2; if(gcp==1) continue; q.insert(num[i]); q.insert(num[i+1]); if(q.size()!=2) continue; ans=max(ans,2); for(Reg int j=i+2;j<=n;++j) { set<long long>::iterator it; Reg long long l1=num[j],gpp=*--q.end(); if(gpp==1) break; Reg int ov=1; for(it=q.begin();it!=q.end();++it) { Reg long long p=*it; if(p>l1) { Reg long long lp=p/l1; if(lp*l1!=p) {ov=0; break;} else { Reg long long y=gcd(gpp,lp); if(y!=gpp&&y!=lp) {ov=0; break;} gpp=y; if(gpp==1) {ov=0; break;} continue; } } else { Reg long long lp=l1/p; if(lp*p!=l1) {ov=0; break;} else { Reg long long y=gcd(gpp,lp); if(y!=gpp&&y!=lp) {ov=0; break;} gpp=y; if(gpp==1) {ov=0; break;} continue; } } } if(!ov) break; Reg long long y=gcd(gcp,gpp); if(y!=gcp&&y!=gpp||y==1) break; gcp=y; l1=q.size(); q.insert(num[j]); l2=q.size(); if(l1==l2) break; ans=max(ans,j-i+1); } } printf("%lld",max(1,ans)); return 0; }
B. 熟练剖分(tree)
首先这个题要明白一个东西:$a/b+a/c≡a*(inv[b]+inv[c]) (mod p)$。
这个题暴力就可以做。
题目要求期望,那么我们可以求每种可能的概率,然后相乘,就得到期望。
对于每个节点,枚举它的每个儿子作为重链,然后再枚举所有儿子的可能的轻链的条数,更新这个节点。
根据上面的式子,我们可以直接将概率 ”相加“ 而不用通分,
最后在$root$节点求一下期望。
丑陋的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstring> #include<cstdio> #include<vector> #define Maxn 3050 #define mod 1000000007 #define Inv(x) (mi((x),mod-2,mod)) #define Reg register using namespace std; const int L=1<<20|1; char buffer[L],*S,*TT; #define getchar() ((S==TT&&(TT=(S=buffer)+fread(buffer,1,L,stdin),S==TT))?EOF:*S++) int n,k,root,du[Maxn]; long long dp[Maxn],p[Maxn][Maxn],vis[Maxn][Maxn]; vector<vector<int> > son(Maxn),vp(Maxn); inline long long max(long long x,long long y) {return x>y?x:y;} inline long long read() { Reg long long a=0,b=1;Reg char ch=getchar(); while(ch<'0'||ch>'9') b=(ch=='-')?-1:1,ch=getchar(); while(ch>='0'&&ch<='9') a=(a<<3)+(a<<1)+(ch^48),ch=getchar(); return a*b; } inline long long mi(Reg long long x,Reg long long y,Reg long long p) { Reg long long ans=1,base=x; while(y) { if(y&1) ans=(ans*base)%p; base=(base*base)%p; y>>=1; } return ans; } inline void dfp(Reg int x,Reg int child,Reg int zchi,Reg long long cnt,Reg long long poz) { if(child==son[x].size()) { p[x][cnt]=(p[x][cnt]+poz*Inv(son[x].size()))%mod; if(!vis[x][cnt]) { vis[x][cnt]=1; vp[x].push_back(cnt); } return; } Reg int k=son[x][child]; for(Reg int i=0;i<vp[k].size();++i) { if(child!=zchi) dfp(x,child+1,zchi,max(cnt,vp[k][i]+1),(p[k][vp[k][i]]*poz)%mod); else dfp(x,child+1,zchi,max(cnt,vp[k][i]),(p[k][vp[k][i]]*poz)%mod); } return; } inline void dfs(Reg int x) { // cout<<x<<endl; for(Reg int i=0;i<son[x].size();++i) dfs(son[x][i]); for(Reg int i=0;i<son[x].size();++i) //i是重儿子 概率1/son[x].size() dfp(x,0,i,0,1); if(!son[x].size()) { p[x][0]=1; vp[x].push_back(0); vis[x][0]=1; } return; } int main() { // freopen("text.in","r",stdin); n=read(); for(Reg int i=1,k;i<=n;++i) { k=read(); for(Reg int j=1,x;j<=k;++j) { x=read(); son[i].push_back(x); ++du[x]; } } for(Reg int i=1;i<=n;++i) if(!du[i]) root=i; dfs(root); Reg long long anp=0; for(Reg int i=0;i<vp[root].size();++i) anp=(anp+p[root][vp[root][i]]*vp[root][i])%mod; printf("%lld",anp); return 0; }