- 上午
- 模拟考试(大悲催…)
- Prob.1(WA)
一个套路,没做过真的好难想出来
简化题目:
对于一个整数序列,把任意一个元素修改为任意一个整数为一次操作,问最少需要几次操作可以使得序列(严格)单调上升。
开始想的是求一个LIS(最长上升子序列),然后发现不对,因为只能修改为整数。
然后就想不出来了,555
正解:
把序列的每个元素的值减去该元素的标号,即a[ i ]-=i ;
然后再求一个最长不下降子序列,这样求出来的最长序列可以保证:在该最长不下降子序列中的元素不修改的情况下,其他元素一定可以修改成功。
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int lson[100005],rson[100005],key[100005],t[100005],now[100005]; int n,cnt; void DFS(int u){ if(lson[u]) DFS(lson[u]); ++cnt; t[cnt]=key[u]-cnt; if(rson[u]) DFS(rson[u]); } void LIS(){ cnt=0; for(int i=1;i<=n;i++){ if(!cnt||now[cnt]<=t[i]){ now[++cnt]=t[i]; } else{ int l=upper_bound(now+1,now+cnt+1,t[i])-now; now[l]=t[i]; } } printf("%d",n-cnt); } int main(){ freopen("binary.in","r",stdin); freopen("binary.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&key[i]); for(int i=2,a,b;i<=n;i++){ scanf("%d%d",&a,&b); if(!b) lson[a]=i; else rson[a]=i; } DFS(1); LIS(); return 0; }
- Prob.1(WA)
- 模拟考试(大悲催…)
- Prob.2(AC)
一个小技巧:一个序列区间的gcd如果等于该区间的最小值,那么这个区间的所有数都可以被该最小值整除。
本题两个ST表维护
- Prob.3(WA)
神题,记忆化搜索
(S->P)反向考虑交换操作,如果最后一次交换的是a[i]和a[i+1],那么必然在该次交换之前,a[l]~a[i]的值都小于a[i+1]~a[r]。
所以对于每个成立的a[i],a[i+1],可以把序列分为两段(左一段右一段),然后递归做相同操作。
然后回溯时对当前递归层的答案贡献
=左段的方案数*右段的方案数*C(r-l-1,i-l),这个组合数考虑两边的交换顺序
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 const int mod=1000000007; 6 int dp[55][55],fac[55],inv[55]; 7 int aa[55],pos[55]; 8 int power(int a,int b) 9 { 10 int val=1; 11 while(b) 12 { 13 if(b&1) val=(1ll*val*a)%mod; 14 a=(1ll*a*a)%mod; b>>=1; 15 } 16 return val; 17 } 18 void pre_fac_inv(int n) 19 { 20 fac[0]=fac[1]=1; 21 for(int i=2;i<=n;i++) fac[i]=(1ll*fac[i-1]*i)%mod; 22 inv[n]=power(fac[n],mod-2); 23 for(int i=n;i>1;i--) inv[i-1]=(1ll*inv[i]*i)%mod; 24 inv[0]=inv[1]; 25 } 26 int C(int m,int n) 27 { 28 return 1ll*fac[m]*inv[m-n]%mod*inv[n]%mod; 29 } 30 int dfs(int l,int r){ 31 if(l>=r) return 1; 32 if(dp[l][r]) return dp[l][r]; 33 int maxx[55],minn[55]; 34 memset(maxx,0,sizeof(maxx)); 35 memset(minn,0x3f,sizeof(minn)); 36 int ret=0,numl,numr,ma,mi; 37 for(int i=l;i<=r;i++){ 38 maxx[i]=aa[i]; 39 if(i!=l) maxx[i]=max(maxx[i],maxx[i-1]); 40 } 41 for(int i=r;i>=l;i--){ 42 minn[i]=min(minn[i],aa[i]); 43 if(i!=r) minn[i]=min(minn[i],minn[i+1]); 44 } 45 for(int i=l;i<r;i++){ 46 swap(aa[i],aa[i+1]); 47 ma=max(maxx[i-1],aa[i]); 48 mi=min(minn[i+2],aa[i+1]); 49 if(ma<mi){ 50 numl=dfs(l,i); 51 numr=dfs(i+1,r); 52 ret=(1ll*ret+1ll*numl*numr%mod*C(r-l-1,i-l)%mod)%mod; 53 } 54 swap(aa[i],aa[i+1]); 55 } 56 return dp[l][r]=ret; 57 } 58 int main(){ 59 freopen("swap.in","r",stdin); 60 freopen("swap.out","w",stdout); 61 int n; 62 scanf("%d",&n); 63 pre_fac_inv(n); 64 for(int i=1;i<=n;i++) scanf("%d",&aa[i]),aa[i]++; 65 int ans=dfs(1,n); 66 printf("%d",ans); 67 return 0; 68 }