雅礼题好难啊。
这个DP题思路好强。
这个东西首先一眼就知道按y排的DP怎么写,大概就是设$f(i,j,k)$表示考虑到y坐标从大到小排名为i的点,这线上一次转是j,上上次转是k的数量,直接二维限制转移就行了。
考虑这东西怎么优化。
前缀和能搞时间,woc空间也被卡了???
打出来表看一看????
这个DP数组有好多都是空的。。。
因为越往后x限制的越少。
然后我就不会了。
正经:设$f(i,0/1)$表示从x坐标排名为i,出门左转还是右转的线的数量。
我一开始就否掉了这东西因为好像转移顺序会出问题。
但是仔细考虑一下。
对于一个点i,如果它的左侧有一个点j比他低,那么j能把自己的右转数量转移给i的左转数量。
如果有一个点j比它高,那么应该是把i的左转转移给j的右转。
但是这时i的左转不能转的比j还靠左否则不合题意。
但是我们可以在转移i的时候先不转移i的右转,然后去枚举左侧j用i去给j做他的右转贡献(先后问题。有人会给i做贡献)。
当我们从大到小枚举比i高的j的时候恰好就有,此时加到的i左转没有比j还小的点的贡献。
那么就可以给j做右转贡献。
所以它很对。
还很快。
还很省空间。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 const int N=6020,mod=1e9+7; 7 int f[N][N]; 8 inline int rd() 9 { 10 int s=0,w=1; 11 char cc=getchar(); 12 for(;cc<‘0‘||cc>‘9‘;cc=getchar()) if(cc==‘-‘) w=-1; 13 for(;cc>=‘0‘&&cc<=‘9‘;cc=getchar()) s=(s<<3)+(s<<1)+cc-‘0‘; 14 return s*w; 15 } 16 struct node{int x,y;}p[N]; 17 bool cmp(node a,node b){return a.x<b.x;} 18 int main() 19 { 20 int n=rd(); 21 for(int i=1;i<=n;i++)p[i].x=rd(),p[i].y=rd(); 22 sort(p+1,p+n+1,cmp); 23 for(int i=1;i<=n;i++) 24 { 25 f[i][0]=f[i][1]=1; 26 for(int j=n;j;j--) 27 { 28 if(p[j].x>=p[i].x)continue; 29 if(p[j].y<p[i].y)f[i][0]=(f[i][0]+f[j][1])%mod; 30 else f[j][1]=(f[j][1]+f[i][0])%mod; 31 } 32 } 33 long long ans=0; 34 for(int i=1;i<=n;i++) 35 ans=((ans+f[i][0])%mod+f[i][1])%mod; 36 printf("%lld\n",(ans-n+mod)%mod); 37 } 38 /* 39 g++ 1.cpp -o 1 40 ./1 41 4 42 2 2 43 3 1 44 1 4 45 4 3 46 */
原文地址:https://www.cnblogs.com/starsing/p/11575105.html
时间: 2024-10-08 14:26:24