清橙A1210. 光棱坦克

问题描述
  一个平面直角坐标系上,有N个点,标号为1到N,其中第i个点的坐标为(x[i], y[i])。
  求满足以下两个条件的点列{p[i]}的数目(假设{p[i]}的长度为M):
  1) 对任意1 <= i < j <= M,必有y[p[i]] > y[p[j]];
  2) 对任意3 <= i <= M,必有x[p[i-1]] < x[p[i]] < x[p[i-2]]或者x[p[i-2]] < x[p[i]] < x[p[i-1]]。
  求满足条件的非空序列{p[i]}的数目,结果对一个整数Q取模。
数据规模和约定
        对于25%的数据,N <= 50;对于40%的数据,N <= 700;对于60%的数据,N <= 2000;对于70%的数据,N <= 4000;对于100%的数据,1 <= N <= 7000。
        对于100%的数据,保证对任何的i,x[i]和y[i]都是1到2000000000之间的整数。
  对于100%的数据,保证有当i != j时,有x[i] != x[j]且y[i] != y[j]。
这题很久以前就做了,当时觉得很简单,现在发现它的思路还是有一点借鉴价值.
首先把点按照x坐标排序(不是y坐标)
设dp[i][j][0/1]代表只考虑前i个点,以第j个点为起点,下一个点在它的左边/右边的方案数.
当i增加1时, 从右到左 对每个之前的点考虑第i个点造成的贡献.
当这个点在第i个点以上时,第i个点可以更新这个点的dp值;
当这个点在第i个点以下时,这个点可以更新第i个点的dp值.
显然是可以滚动数组的.
复杂度O(n*n)
说来当时我想了一天,试图优化成O(nlogn) 的复杂度,没想到7000的数据平方可以过......还是清橙上最快的......
所有点的横纵坐标都不相等,所以细节很少
具体做法见代码:
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    struct node{
        int x,y;
    }pot[7010];
    bool cmpx(node A,node B)
    {
        return A.x<B.x;
    }
    int n,md;
    int dp[7010][2];
    int main(){
        scanf("%d%d",&n,&md);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&pot[i].x,&pot[i].y);
        sort(pot+1,pot+n+1,cmpx);
        for(int i=1;i<=n;i++)
        {
            dp[i][0]=dp[i][1]=1;
            for(int j=i-1;j>=1;j--)
            {
                if(pot[j].y<pot[i].y)
                {
                    dp[i][0]+=dp[j][1];
                    if(dp[i][0]>=md) dp[i][0]-=md;
                }
                else
                {
                    dp[j][1]+=dp[i][0];
                    if(dp[j][1]>=md) dp[j][1]-=md;
                }
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            ans+=dp[i][0];
            if(ans>=md) ans-=md;
            ans+=dp[i][1];
            if(ans>=md) ans-=md;
        }
        ans-=n;
        if(ans<0) ans+=md;
        printf("%d\n",ans);
        return 0;
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值