您的位置:首页 > 其它

湖南NOIP集训模拟题DAY1 BY ExfJOE [贪心][DP][二分]

2016-10-12 18:00 489 查看
解题报告:

一. 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息