湖南NOIP集训模拟题DAY1 BY ExfJOE [贪心][DP][二分]
2016-10-12 18:00
489 查看
解题报告:
一. Maximum
题意:给定一串序列,根据输入的变量求其中的任意两个变量xor,and或or的最大值;
分析:
Std:FWT;
不会的话,and可以用每个位上有1的个数来贪心判断,具体的实现就是递归位数,把当前正在枚举的位数为1的数存在一个数组里,如果当前位数为1的数大于等于二就把筛选后数组传入下一步,否则把筛选前数组传入下一步;
二. Bridge
题意:给定坐标轴上的点的坐标和移动方向,求某时间之后某个点的位置,两个点在遇到的瞬间改变方向,每组数据包括多次查询;
分析:首先,每个点遇到的时候立即改变方向,即点的相对位置不会改变。
然后,两个点相遇以后可以看做两个点交换编号并且穿过。
所以对于当前时间,对于当前状态可以O(1)求出任意点编号转换后的位置;
所以这道题包括两次二分思想,一次是针对当前时间二分位置,然后可以求出当前位置前面的点和后面的点有多少个。就可以判断当前点在第几。
然后对不同方向的点分别排序,二分查找有多少点在当前位置的前面(因为速度确定,那么对于每一种方向,需要在某个点之前才能在当前点之前的数值也唯一确定);
然后要注意的就是,当满足情况的时候要多次右移或左移,取决于参考的是当前点之前还是之后的点数,这样才能确定当前枚举的位置就是那个点刚好的位置。
三. Group
题意:对给定数据分组,使得每一组数据的极差和不超过K,求分组的方式;
分析:用F[I][J][k]表示处理到i点,还有J组没有确定最大值,一共极差和已经是k的情况一共有多少种,那么最终的答案就是F
[0][K],K<=kmaxn的和,显然我们知道,当处理到i时,除了i-1的数据,剩下的数据都没有用,所以这里可以用滚动数组cur和nxt来存储数据,节约空间。
对于每个点有四种情况,一种是新建一组不加,一种是新建一组等待最大值,一种是加入一组等待最大值,一种是加入一组不加。注意,要处理加入一组的最大值问题,本题输入顺序需要排序。
然后就是,对于代价,用差分的方式,每次加上两个点的差乘以j,因为只有没确定最大值的点才需要继续加,每确定一个点,它修改的状态的j就减一,保证了该状态的该组不再被加。
一. Maximum
题意:给定一串序列,根据输入的变量求其中的任意两个变量xor,and或or的最大值;
分析:
Std:FWT;
不会的话,and可以用每个位上有1的个数来贪心判断,具体的实现就是递归位数,把当前正在枚举的位数为1的数存在一个数组里,如果当前位数为1的数大于等于二就把筛选后数组传入下一步,否则把筛选前数组传入下一步;
#include<cstdio> #include<cstring> using namespace std; const int maxn=1<<20,maxn2=1e5; int n,c,t,a[maxn2],b[maxn],exi[maxn*2+5],ans; void buildy(int u,int ste,int cur) { exi[cur]=1; if(ste==-1)return; if(a[u]&(1<<ste))buildy(u,ste-1,2*cur+1); else buildy(u,ste-1,2*cur); } int lookfor(int u,int ste,int cur) { if(ste==-1)return 0; if(a[u]&(1<<ste)&&exi[2*cur]) return lookfor(u,ste-1,2*cur)+(1<<ste); else if((!(a[u]&(1<<ste)))&&exi[2*cur+1]) return lookfor(u,ste-1,2*cur+1)+(1<<ste); else if(exi[2*cur]) return lookfor(u,ste-1,2*cur); return lookfor(u,ste-1,2*cur+1); } void work1(int *num,const int nn,int len) { int s[nn],nxt=0; for(int i=len;i>=0;i--){ for(int j=1;j<=nn;j++)if(num[j]&(1<<i))s[++nxt]=num[j]; if(nxt>1){work1(s,nxt,i-1); ans+=1<<i;return; } memset(s,0,sizeof(s));nxt=0; } return ; } int work2() { int mx=0;memset(exi,0,sizeof(exi)); for(int i=1;i<=n;i++) buildy(i,19,1); for(int i=1;i<=n;i++) mx=max(lookfor(i,19,1),mx); return mx; } int work3() { memset(b,0,sizeof(b));int mx=0; for(int i=1;i<=n;i++)b[a[i]]=1; for(int i=0;i<20;i++)for(int j=0;j<maxn;j++)if(j&(1<<i)) b[j^(1<<i)]|=b[j]; for(int i=1;i<=n;i++){ int ans=0,tmp=0; for(int j=19;j>=0;j--)if((!(a[i]&(1<<j)))&&b[tmp|(1<<j)]){ ans|=1<<j;tmp|=1<<j; } else if(a[i]&(1<<j))ans|=1<<j; mx=max(mx,ans); } return mx; /*for(int i=1;i<=n;i++)b[a[i]]=1; for(int i=0;i<=20;i++) for(int j=0;j<=maxn;j++) if(j&(1<<i))b[j^(1<<i)]|=b[j]; int mx=0; for(int i=1;i<=n;i++) { int ans=a[i]; int temp=0; for(int j=20;j>=0;j--) if(!(a[i]&(1<<j))) if(b[temp|(1<<j)]) { ans|=(1<<j); temp|=(1<<j); } mx=max(mx,ans); } return mx;*/ } int main() { freopen("maximum.in","r",stdin); freopen("maximum.out","w",stdout); scanf("%d",&t); for(int i=1;i<=t;i++){ scanf("%d %d",&n,&c); for(int i=1;i<=n;i++)scanf("%d",&a[i]); if(c==1)ans=0,work1(a,n,19),printf("%d\n",ans); else if(c==2)printf("%d\n",work2()); else printf("%d\n",work3()); } return 0; }
二. Bridge
题意:给定坐标轴上的点的坐标和移动方向,求某时间之后某个点的位置,两个点在遇到的瞬间改变方向,每组数据包括多次查询;
分析:首先,每个点遇到的时候立即改变方向,即点的相对位置不会改变。
然后,两个点相遇以后可以看做两个点交换编号并且穿过。
所以对于当前时间,对于当前状态可以O(1)求出任意点编号转换后的位置;
所以这道题包括两次二分思想,一次是针对当前时间二分位置,然后可以求出当前位置前面的点和后面的点有多少个。就可以判断当前点在第几。
然后对不同方向的点分别排序,二分查找有多少点在当前位置的前面(因为速度确定,那么对于每一种方向,需要在某个点之前才能在当前点之前的数值也唯一确定);
然后要注意的就是,当满足情况的时候要多次右移或左移,取决于参考的是当前点之前还是之后的点数,这样才能确定当前枚举的位置就是那个点刚好的位置。
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int maxn=2e5 +5; int pos[maxn],dir[maxn],rk[maxn],lef[maxn],rig[maxn]; int n,rigcnt,lefcnt,q,num,tii; int main() { freopen("bridge.in","r",stdin); freopen("bridge.out","w",stdout); scanf("%d",&n); for(int i=0;i<n;i++)scanf("%d",&pos[i]); for(int i=0;i<n;i++)scanf("%d",&dir[i]); for(int i=0;i<n;i++){ rk[i]=pos[i]; if(dir[i])rig[rigcnt++]=pos[i]; else lef[lefcnt++]=pos[i]; } sort(rk,rk+n);sort(rig,rig+rigcnt);sort(lef,lef+lefcnt); scanf("%d",&q); for(int i=1;i<=q;i++){ scanf("%d %d",&num,&tii); long long l=rk[0]-tii,r=rk[n-1]+tii; int x=lower_bound(rk, rk + n, pos[num]) - rk +1; while(l<=r){ long long mid=(l+r)/2; int tmp1=(upper_bound(rig,rig+rigcnt,mid-tii)-rig ) +(upper_bound(lef,lef+lefcnt,mid+tii)-lef ); if(tmp1<x)l=mid+1; else r=mid-1; } printf("%d\n",(int)l); } return 0; }
三. Group
题意:对给定数据分组,使得每一组数据的极差和不超过K,求分组的方式;
分析:用F[I][J][k]表示处理到i点,还有J组没有确定最大值,一共极差和已经是k的情况一共有多少种,那么最终的答案就是F
[0][K],K<=kmaxn的和,显然我们知道,当处理到i时,除了i-1的数据,剩下的数据都没有用,所以这里可以用滚动数组cur和nxt来存储数据,节约空间。
对于每个点有四种情况,一种是新建一组不加,一种是新建一组等待最大值,一种是加入一组等待最大值,一种是加入一组不加。注意,要处理加入一组的最大值问题,本题输入顺序需要排序。
然后就是,对于代价,用差分的方式,每次加上两个点的差乘以j,因为只有没确定最大值的点才需要继续加,每确定一个点,它修改的状态的j就减一,保证了该状态的该组不再被加。
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int mody=1e9+7; const int maxn=205,maxn2=1005; int n,a[maxn],f[2][maxn][maxn2],kava,cur,nxt,ans; int main() { freopen("group.in","r",stdin); freopen("group.out","w",stdout); scanf("%d %d",&n,&kava); for(int i=0;i<n;i++)scanf("%d",&a[i]); sort(a,a+n); cur=0;nxt=1;f[cur][1][0]=f[cur][0][0]=1; for(int i=1;i<n;i++){ for(int j=0;j<=i+1;j++)for(int k=0;k<=kava;k++){ int v=f[cur][j][k];f[cur][j][k]=0; if(!v)continue; int t=k+(a[i]-a[i-1])*j; if(t>kava)continue; (f[nxt][j][t]+=v)%=mody; (f[nxt][j+1][t]+=v)%=mody; (f[nxt][j][t]+=(long long)v*j%mody)%=mody; if(j)(f[nxt][j-1][t]+=(long long)v*j%mody)%=mody; } swap(cur,nxt); } for(int i=0;i<=kava;i++)(ans+=f[cur][0][i])%=mody; printf("%d",ans); return 0; }
相关文章推荐
- 【NOIP 模拟题】[T2] 王者荣耀(二分答案+dp)
- NOIP模拟题 River Path Word[排序][贪心][DP]
- NOIP模拟题 2016.10.18 [二分答案] [从上到下的树形DP] [链表翻转]
- 【noip模拟题】[dp][二分][树链剖分][hdu5029][线段树]
- NOIP模拟题 2016.8.27 [贪心] [DP] [计数问题]
- NOIP模拟题 [DP][二分][树剖][树上差分]
- 【NOIP模拟题】【贪心】【动态规划DP】2016.11.12第二题题解
- NOIP模拟题[贪心][DP][数论]
- NOIP模拟题 2016.10.5 [Trie] [数学] [二分答案] [杂题] [复杂状态DP]
- 【NOIP 模拟题】[山东多校联合模拟赛 day1 T2] 祖先(dp)
- hzwer2015.9.13 NOIP模拟题 explo seq earth[DP][数论][二分][SPFA]
- 陕西省集训day1(枚举,贪心,二分)
- 【NOIP 模拟题】[T1]连锁店(贪心)
- LIS(最长上升子序列)的 DP 与 (贪心+二分) 两种解法
- [2017湖南集训7-7]第一题 DP
- NOIP模拟题 2016.10.13 [贪心] [记忆化搜索]
- Codeforces Round #424 -(二分&贪心)||dp-D. Office Keys
- Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增)
- NOIP模拟题 [DP][RMQ][分块]
- BZOJ2097: [Usaco2010 Dec]Exercise 奶牛健美操 贪心+伪树dp+二分