4
7
2016
0

【JLOI2013】【bzoj3090~3093】|赛车|卡牌游戏|删除物品|地形生成

T1 赛车【计算几何?+单调栈/队列】

抽象模型:

v-t图:赛车==直线Xi,t=Vi*t+Ki;追上==直线焦点;曾经领先==“水平可见”

单调队列维护

学习了Regina8023的写法:用队列保存当前为答案的元素的下标
单调队列:队列中下标对应直线单调递增,其实维护了一个下凸线

交点在x轴左侧:斜率较小的直线无法成为答案,从前往后扫,向后移动头指针
因为:具有单调性!该种情况不可能在中间出现

bool cmp1(car a,car b)
{return a.v<b.v || (a.v==b.v&&a.K>b.K);}




    sort(a+1,a+n+1,cmp1);
    a[0].v=-1;
    r=0;
    F(i,1,n){
        if(a[i].v==a[i-1].v&&a[i].K<a[i-1].K) continue;
        while(r>1 && poix(a[i],a[q[r]])<poix(a[q[r]],a[q[r-1]])) r--;
        q[++r]=i;
    }
    l=1;
    while(l<r && poix(a[q[l]],a[q[l+1]])<-eps) l++;

被bzoj卡了,cena测ac

输出方式

bool cmp2(int x,int y){return a[x].id<a[y].id;}
    
    printf("%d\n",r-l+1);
    sort(q+l,q+r+1,cmp2);
    printf("%d",a[q[l]].id);
    F(i,l+1,r) printf(" %d",a[q[i]].id);

注意sort左闭右开

模拟time:追上==解方程得t表达式:

double poix(car a,car b)//交点横坐标即为相遇tim! 保证x.K<y.K
{return (double)(a.K-b.K)/(b.v-a.v);}

 

单调栈维护


T2 卡牌游戏【概率递推】

状态:ans[i][j]表示当前剩余i个人的回合,第j个人最后可以获胜的概率

j是相对当前回合坐庄的人的编号

ans[1][1]=0

从小往大三重循环枚举i,j,k(所抽取的卡牌)

i,j由i-1,next转移过来,next由当前j决定,i-1所有状态的答案在之前已经得出,故可递推计算

类似记忆化搜索的思想?

    ans[1][1]=1;
    F(i,1,n){
        F(j,1,i){//now bianhao
            F(k,1,m){
                int w=((int)c[k]%i)?(int)c[k]%i:i;//被淘汰的元素
                int next=(j>w)?(j-w):(i-w+j);
                ans[i][j]+=ans[i-1][next]/(double)m;
            }
        }
    }

输出%方式:两个%%

   F(i,1,n-1) printf("%.2lf%% ",ans[n][i]*100);
    printf("%.2lf%%",ans[n][n]*100);

 

 

另:暴力分:搜索模拟一次游戏,枚举若干次(>1000)游戏得到结果,近似算出答案——精确度要求不高时可做


T3 删除物品【树状数组/线段树+模拟】

关键点:

整体移动物品,在两堆中顺序相反==>拼接

存在物品:1/删除物品:0==>单点修改,区间查询

  • 单个元素==>整体处理
  • 数据结构的用处:模拟过程!<==抽象模型

注意巧妙的排序方式

 bool cmp(int x,int y){return a[x]>a[y];}  

 

  
    n1=getint();n2=getint();
    n=n1+n2;
    D(i,n1,1) a[i]=getint();
    F(i,n1+1,n) a[i]=getint();
    top1=n1;top2=n1+1;
    B.clear();
    F(i,1,n) id[i]=i,B.add(i,1);//当前元素存在,0表示不存在
    sort(id+1,id+n+1,cmp);
    F(i,1,n){//相当于a[i]从大到小排序
        int now=id[i];
        if(now>=top2){//当前最大在第二堆
            ans+=B.query(top2,now-1);//弹出之前的元素,记录个数!
            B.add(now,-1);//删除该元素,即将该元素的值赋为0
        }
        else{//当前最大在第一堆
            ans+=B.query(now+1,top1);
            B.add(now,-1);
        }
        top1=now-1;top2=now+1;//元素在now出删除
    }

 


T4 地形生成【dp前缀和优化+组合计数】

蛮具有思维难度的题:

第一问:可以发现对一座山有影响的只可能是比它高的山,所以我们可以将山按高度从大到小排序,依次插入每座山。对于高度相同的山一起处理,按关键值从小到大排序,然后将每座山能插入的位置数乘到答案中,即min(i,a[i].key+1)+num-1,num为它在高度相同的山中的排名。

第二问:为了不重复计算,我们每次将高度相同的山拿出来,然后让插入之后的顺序也不改变。这样就可以DP计算,f[i][j]=f[i-1][0]+f[i-1][1]+……+f[i-1][j],其实f数组还可以降到一维。注意每次计算时要将f数组清零。

inline bool cmp(data x,data y)
{
	return x.h==y.h?x.k<y.k:x.h>y.h;
}
	F(i,1,n) a[i].h=read(),a[i].k=read()-1;
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i=j)
	{
		memset(f,0,sizeof(f));
		f[0]=1;
		for(j=i;j<=n&&a[i].h==a[j].h;j++)
		{
			ans1=ans1*(min(i,a[j].k+1)+j-i)%mod;
			for(int k=1;k<i&&k<=a[j].k;k++) f[k]=(f[k]+f[k-1])%mod;
		}
		int sum=0;
		for(int k=0;k<i&&k<=a[j-1].k;k++) sum=(sum+f[k])%mod;
		ans2=(ans2*sum)%mod;
	}


 


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com