10-19 AHS of FCGRC 模拟赛
原题显然可以化为选择若干个数使得它们在“1“位上没有重复(^的本质是不进位加法,只要不进位就没有损失)。
考虑对于每个端点l,找到最远的端点r使得这个[l,r]区间满足题意,那么这里有r-l+1种满足题意的方案。
显然这是单调的,考虑双指针维护解决问题。
我一开始把题意看成i|j==k的方案,结果一个小时之后才发现看挂了。
最后才发现,其实原题意就是看错题意答案的前缀最大值,考虑维护子集的最大值和次大值,接着套上一个状压dp即可解决。
附代码:
A:
#include<cstdio> int n,a[200050]; bool mark[25]; long long ans; void undo(int x){ int cnt=0; while(x){ if(x&1) mark[cnt]=false; ++cnt; x>>=1; } return ; } bool check(int x){ int cnt=0; while(x){ if((x&1)&&mark[cnt]) return false; ++cnt; x>>=1; } return true; } void ins(int x){ int cnt=0; while(x){ if(x&1) mark[cnt]=true; ++cnt; x>>=1; } return ; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); int st=0,en=0; while(st<=n){ if(st!=0) undo(a[st]); ++st; while(en<n){ if(check(a[en+1])) ins(a[++en]); else break; } ans+=en-st+1; } printf("%lld\n",ans); return 0; }
B:
#include<cstdio> #include<cstring> #include<algorithm> struct node{ int mins,id1; int smin,id2; }dp[262149]; using std::min; using std::max; int n,a[262149]; void merge(int i,int j){ if(dp[i].mins<dp[j].mins){ dp[i].smin=max(dp[i].mins,dp[j].smin); dp[i].id2=dp[i].mins>dp[j].smin?dp[i].id1:dp[j].id2; dp[i].mins=dp[j].mins; dp[i].id1=dp[j].id1; } else if(dp[i].smin<dp[j].mins&&dp[j].id1!=dp[i].id1) dp[i].smin=dp[j].mins,dp[i].id2=dp[j].id1; return ; } int main(){ scanf("%d",&n); memset(dp,0,sizeof dp); for(int i=0;i<(1<<n);++i) scanf("%d",&a[i]); dp[0]=(node){a[0],0,-1,-1}; for(int i=1;i<(1<<n);++i){ if(dp[i].smin) continue; dp[i]=(node){a[i],i,-1,-1}; for(int j=0;j<n;j++) if((1<<j)&i) merge(i,i^(1<<j)); } int lans=-1; for(int k=1;k<(1<<n);k++){ printf("%d\n",lans=max(lans,dp[k].smin+dp[k].mins)); } return 0; }
C题不会,走了。