zoukankan      html  css  js  c++  java
  • [JZOJ1901] 【2010集训队出题】光棱坦克

    题目

    题目大意

    给你个平面上的一堆点,问序列({p_i})的个数。
    满足(y_{p_{i-1}}>y_{p_i})并且(x_{p_i})(x_{p_i-1})(x_{p_i-2})之间。


    正解

    我不知道为什么我的树状数组打挂了……尽管不一定能AC,但是WA了……

    这题的正解有很多,最为传奇的,则是彭大爷的神仙解法。
    显然这是个DP,而他抛弃了按照(y)从大到小排序的传统做法,反而是以(x)从小到大排序。将({p_i})倒过来做。设(f_{i,0/1})表示到(i)这个点,上一个点在左边或者右边的方案数。
    DP的时候(i)从左到右扫过去,然后从右到左枚举(j),有两种转移:
    如果(y_j<y_i),则从(f_{j,1})转移到(f_{i,0})
    如果(y_j>y_i),则从(f_{i,0})转移到(f_{j,1})
    这样的转移为什么是对的?实际上随便画个图就能理解了。
    具体来说,在第一类转移的时候,很显然之前转移到(f_{j,1})的是(j)(i)之间的状态;
    在第二类转移的时候,很显然之前转移到(f_{i,0})的是(j)(i)之间的状态。
    这样就保证了题目要求的性质。


    代码

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 7010
    inline int input(){
    	char ch=getchar();
    	while (ch<'0' || '9'<ch)
    		ch=getchar();
    	int x=0;
    	do{
    		x=x*10+ch-'0';
    		ch=getchar();
    	}
    	while ('0'<=ch && ch<='9');
    	return x;
    }	
    int n,m,mo;
    struct Node{
    	int x,y;
    } d[N];
    inline bool cmpd(const Node &a,const Node &b){return a.x<b.x;}
    int f[N][2];
    int main(){
    	n=input(),mo=input();
    	for (int i=1;i<=n;++i)
    		d[i]={input(),input()};
    	sort(d+1,d+n+1,cmpd);
    	for (int i=1;i<=n;++i){
    		f[i][0]=f[i][1]=1;
    		for (int j=i-1;j>=1;--j)
    			if (d[j].y<d[i].y)
    				(f[i][0]+=f[j][1])%=mo;
    			else
    				(f[j][1]+=f[i][0])%=mo;
    	}
    	long long ans=0;
    	for (int i=1;i<=n;++i)
    		ans+=f[i][0]+f[i][1];
    	printf("%lld
    ",((ans-n)%mo+mo)%mo);
    	return 0;
    }
    

    总结

    这样的DP真是太鬼畜了……
    彭大爷牛逼!!!
    %%%

  • 相关阅读:
    多线程与MySQL(十)
    多进程与多线程(九)
    异常处理与网络编程(八)
    面向对象,绑定方法与异常处理(七)
    模块与对象(六)
    包与模块(五)
    迭代器与函数Python学习(四)
    函数与装饰器Python学习(三)
    数据库
    并发编程
  • 原文地址:https://www.cnblogs.com/jz-597/p/11423155.html
Copyright © 2011-2022 走看看