「BZOJ3688」「FJ2014集训」折线统计
「题目描述」
二维平面上有n个点(xi, yi),现在这些点中取若干点构成一个集合S,对它们按照x坐标排序,顺次连接,将会构成一些连续上升、下降的折线,设其数量为f(S)。如下图中,1->2,2->3,3->5,5->6(数字为下图中从左到右的点编号),将折线分为了4部分,每部分连续上升、下降。
现给定k,求满足f(S) = k的S集合个数。
「输入格式」
第一行两个整数n和k,以下n行每行两个数(xi, yi)表示第i个点的坐标。所有点的坐标值都在[1, 100000]内,且不存在两个点,x坐标值相等或y坐标值相等。
「输出格式」
输出满足要求的方案总数 mod 100007的结果。
「样例输入」
5 1
5 5
3 2
4 4
2 3
1 1
「样例输出」
19
「数据范围」
对于10%的数据,n <= 10, k = 1
对于30%的数据,n <= 1000, k = 1
对于50%的数据,n <= 1000, k <= 10
对于100%的数据,n <= 50000,0 < k <= 10
「题解」
对于n<=1000直接即可
dp[i][j][0/1]表示以i为结尾,有j段,最后一段是上升or下降的折线方案
正解随便搞个树状数组什么的套一下就好了,类似二维偏序最长链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #define ll long long #define inf 100000000 #define mod 100007 using namespace std; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,m,ans; int t[15][2][100005]; int f[100005][15][2]; struct data{int x,y;}p[100005]; inline bool operator<(data a,data b) {return a.x<b.x;} inline int lowbit(int x) {return x&(-x);} inline void add(int x,int v,int j,int k) { for(int i=x;i<=100000;i+=lowbit(i)) t[j][k][i]=(t[j][k][i]+v)%mod; } inline int que(int x,int j,int k) { int sum=0; for(int i=x;i;i-=lowbit(i)) sum=(sum+t[j][k][i])%mod; return sum; } void solve1() { for(int i=1;i<=n;i++) { f[i][0][0]=f[i][0][1]=1; for(int j=1;j<i;j++) for(int k=1;k<=m;k++) { if(p[j].y<p[i].y)f[i][k][0]+=f[j][k][0]+f[j][k-1][1]; else f[i][k][1]+=f[j][k][1]+f[j][k-1][0]; f[i][k][0]%=mod;f[i][k][1]%=mod; } } for(int i=1;i<=n;i++) { ans=(ans+f[i][m][0])%mod; ans=(ans+f[i][m][1])%mod; } printf("%d\n",ans); } void solve2() { for(int i=1;i<=n;i++) { f[i][0][0]=f[i][0][1]=1; add(p[i].y,1,0,0);add(p[i].y,1,0,1); for(int j=1;j<=m;j++) { f[i][j][0]+=que(p[i].y-1,j,0)+que(p[i].y-1,j-1,1); f[i][j][1]+=que(100000,j,1)-que(p[i].y,j,1)+que(100000,j-1,0)-que(p[i].y,j-1,0); f[i][j][0]%=mod;f[i][j][1]%=mod; if(f[i][j][1]<0)f[i][j][1]+=mod; add(p[i].y,f[i][j][0],j,0);add(p[i].y,f[i][j][1],j,1); } } for(int i=1;i<=n;i++) { ans=(ans+f[i][m][0])%mod; ans=(ans+f[i][m][1])%mod; } printf("%d\n",ans); } int main() { //freopen("line.in","r",stdin); //freopen("line.out","w",stdout); n=read(); m=read(); for(int i=1;i<=n;i++) p[i].x=read(),p[i].y=read(); sort(p+1,p+n+1); if(n<=1000)solve1(); else solve2(); return 0; } |
Subscribe