T1、
原本以为是水题的,但是题目里有这么一句话”不模1e9+7“。。。。
可以注意到上下左右都要求单调增,那么状态就很好确定了
f[i][j]表示第一行放了前i个格子,第二行放了前j个格子,并且这些数都是小于等于i+j的
转义很好写:f[i][j]可以推给f[i+1][j]和f[i][j+1]。需要时时保证i>j
另外注意此处格子是否可放。
由于不取模,需要用高精。但是实现只有0.2s
——卡常!
最后还是被卡了20分——本机测试不超时的
订正的时候发现用long long压18位居然就能过了,而9位int死活不过。。。。
还有有些人用这个不算开挂吗? __attribute__((optimize("O2")))
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const long long Mod = (1e18); int a[2][1005]; int n,i,j; struct BITINT{ int h; long long a[40]; BITINT operator +(const BITINT &x) const { if (h==0) return x; BITINT ret; memset(ret.a,0,sizeof(ret.a)); ret.h = max(h, x.h); for (int i=0;i<ret.h||ret.a[i+1]>0;i++) { ret.a[i] += a[i]+x.a[i]; while (ret.a[i]>=Mod) ret.a[i+1]++, ret.a[i]-=Mod; } while (ret.a[ret.h]>0) ret.h++; //for (int i=ret.h;i<70;i++) ret.a[i]=0; return ret; } void print(){ if (h==0) {printf("0\n");return;} printf("%lld",a[h-1]); for (int i=h-2;i>=0;i--){ long long x = Mod/10; if (a[i]==0) {printf("000000000000000000");continue;} while (a[i]<x) {printf("0");x/=10;} printf("%lld",a[i]); } printf("\n"); } } f[1005][1005]; int main(){ scanf("%d",&n); for (i=1;i<=n;i++) scanf("%d",&a[0][i]); for (i=1;i<=n;i++) scanf("%d",&a[1][i]); f[0][0].h = f[0][0].a[0] = 1; for (i=0;i<=n;i++) for (j=0;j<=i;j++) if (f[i][j].h>0){ if (i<n && (a[0][i+1]==0 || a[0][i+1]==i+j+1)) f[i+1][j] = f[i+1][j] + f[i][j]; if (j<i && (a[1][j+1]==0 || a[1][j+1]==i+j+1)) f[i][j+1] = f[i][j+1] + f[i][j]; } f[n][n].print(); return 0; }
shtsc2011的原题。
凸包+旋转卡壳,脑补脑补就知道了。。。。
#include <cmath> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int Maxn = 200005; int n,m,i,j,upcnt,dwcnt; int opp[Maxn]; double ans, dis1[Maxn], dis2[Maxn]; struct Point { int x, y; void read() { scanf("%d%d",&x,&y); } bool operator <(const Point &a)const { return x<a.x || (x==a.x && y<a.y); } Point operator *(const int &a)const { return (Point){x*a, y*a}; } Point operator +(const Point &a)const { return (Point){x+a.x, y+a.y}; } Point operator -(const Point &a)const { return (Point){x-a.x, y-a.y}; } double len() { return sqrt(1.*x*x+1.*y*y); } } P, dot[Maxn], up[Maxn], dw[Maxn]; int mult(Point P1,Point P2) { if ((LL)P1.x*P2.y>(LL)P1.y*P2.x) return 1; if ((LL)P1.x*P2.y<(LL)P1.y*P2.x) return -1; return 0; } int mult(Point P0,Point P1,Point P2) { return mult(P1-P0,P2-P0); } void convex_hull(){ sort(dot+1,dot+n+1); up[1] = dot[1]; up[2] = dot[2]; upcnt = 2; for (i=3;i<=n;i++){ while (upcnt>1 && mult(up[upcnt-1],up[upcnt],dot[i])>=0 ) upcnt--; up[++upcnt] = dot[i]; } dw[1] = dot[1]; dw[2] = dot[2]; dwcnt = 2; for (i=3;i<=n;i++){ while (dwcnt>1 && mult(dw[dwcnt-1],dw[dwcnt],dot[i])<=0 ) dwcnt--; dw[++dwcnt] = dot[i]; } for (i=1;i<upcnt;i++) dot[++m] = up[i]; for (i=dwcnt;i>1;i--) dot[++m] = dw[i]; } void find_opp(int i,int &j){ for (;true;j=j%m+1){ int t1 = mult(dot[i%m+1]-dot[i], dot[j]-dot[j-1]); int t2 = mult(dot[i%m+1]-dot[i] ,dot[j%m+1]-dot[j]); if (t1*t2<=0) return; } } double MULT(Point P1,Point P2) { return 1.*P1.x*P2.y-1.*P1.y*P2.x; } double Distance(Point P1,Point P2){ double ret = MULT(P1,P2); if (ret<0) ret = -ret; ret /= P1.len(); return ret; } void calc(int i,int j1,int j2){ for (int j=j1;j!=j2%m+1;j=j%m+1){ Point Q = P*2-(dot[i]+dot[j]); int t1 = mult(Q,dot[j]-dot[j-1]) * mult(Q,dot[j%m+1]-dot[j]); int t2 = mult(Q,dot[i]-dot[i-1]) * mult(Q,dot[i%m+1]-dot[i]); if (t1<=0 && t2<=0){ double d1 = Distance( Q, dot[i]-P ); double d2 = Distance( Q, dot[j%m+1]-P ); double d3 = Distance( Q, dot[(j+1)%m+1]-P ); ans = fmin( ans, fmax(d1, fmax(d2, d3) ) ); } } } #define fmin(x,y) ( (x)<(y)?(x):(y) ) #define fmax(x,y) ( (x)>(y)?(x):(y) ) const double Eps = 1e-12; void work(){ //for (i=1;i<=m;i++) printf("%d %d\n",dot[i].x,dot[i].y); dot[0] = dot[m]; ans = 1e18; for (i=1,j=3;i<=m;i++){ find_opp(i,j); opp[i] = j; double t1 = Distance( (dot[i%m+1]-dot[i]), (dot[i]-P) ); double t2 = Distance( (dot[i%m+1]-dot[i]), (dot[i%m+1]-P) ); double t3 = Distance( (dot[i%m+1]-dot[i]), (dot[j]-P) ); double t4 = Distance( (dot[i%m+1]-dot[i]), (dot[j%m+1]-P) ); if (t2>t1) t1 = t2; if (t4>t3) t3 = t4; dis1[i] = t1; dis2[i] = t3; ans = fmin(ans, fmax(t1, t3) ); } for (i=1;i<=m;i++){ if (dis2[i]-dis1[i]<=Eps && dis1[i%m+1]-dis2[i%m+1]<=Eps ) calc(i%m+1,opp[i],opp[i%m+1]); if (dis1[i]-dis2[i]<=Eps && dis2[i%m+1]-dis1[i%m+1]<=Eps ) calc(i%m+1,opp[i],opp[i%m+1]); } ans = (double)floor(ans*1000) / 1000.; printf("%.3lf\n",ans); } int main(){ //freopen("t2.in","r",stdin); //freopen("t2.out","w",stdout); scanf("%d",&n); P.read(); for (i=1;i<=n;i++) dot[i].read(); convex_hull(); work(); return 0; }
压轴神题
思路很好
只要我们知道长方形内最高点,最低点,最左点和最右点,预处理这些点之间的上下凸壳就可以合并求答案了。
找最点可以用二分查找矩形内是否有点在logn的时间内搞定。(我会说我之前求矩形内是否有点写的是二维树状数组,平白无故多了两个log然后T得飞起吗?)
用f1[i][j]表示在点i和点j围成的矩形内的上凸壳的面积,f2[i][j]表示在点i和点j围成的矩形内的下凸壳的面积,预处理可以做到O(n^2)
代码很呵呵
#include <vector> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int Maxn = 3005; typedef long long LL; int n,m,Q,k,i,j,tx,ty; int a,b,c,d,A,B,C,D; int nx,ny,upcnt,dwcnt; int dw[Maxn], up[Maxn]; int ax[Maxn], ay[Maxn]; int sum[Maxn][Maxn]; LL ans, f1[Maxn][Maxn], f2[Maxn][Maxn]; vector <int> ex[Maxn], ey[Maxn]; struct Point { int x, y; void read() { scanf("%d%d",&x,&y); } bool operator <(const Point &a)const { return x<a.x || (x==a.x && y<a.y); } Point operator -(const Point &a)const { return (Point){x-a.x, y-a.y}; } } dot[Maxn], Dot[Maxn]; LL mult(Point P0,Point P1) { return (LL)P0.x*P1.y - (LL)P1.x*P0.y; } LL mult(Point P0,Point P1,Point P2) { return mult(P1-P0,P2-P0); } int query(int x1,int x2,int y1,int y2) { return sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1]; } void init(){ for (i=1;i<=n;i++){ up[1] = i; upcnt = 1; for (j=i-1;j>0;j--) if (dot[i].y>=dot[j].y) {up[++upcnt] = j; break;} for (j--;j>0;j--) if (dot[i].y>=dot[j].y){ while (upcnt>1 && mult(dot[up[upcnt-1]], dot[up[upcnt]], dot[j])<=0 ) upcnt--; f1[j][i] = f1[up[upcnt]][i] + mult(dot[i], dot[up[upcnt]], dot[j]); up[++upcnt] = j; } up[1] = i; upcnt = 1; for (j=i+1;j<=n;j++) if (dot[i].y>=dot[j].y) {up[++upcnt] = j; break;} for (j++;j<=n;j++) if (dot[i].y>=dot[j].y){ while (upcnt>1 && mult(dot[up[upcnt-1]], dot[up[upcnt]], dot[j])>=0 ) upcnt--; f1[i][j] = f1[i][up[upcnt]] - mult(dot[i], dot[up[upcnt]], dot[j]); up[++upcnt] = j; } dw[1] = i; dwcnt = 1; for (j=i-1;j>0;j--) if (dot[i].y<=dot[j].y) {dw[++dwcnt] = j; break;} for (j--;j>0;j--) if (dot[i].y<=dot[j].y){ while (dwcnt>1 && mult(dot[dw[dwcnt-1]], dot[dw[dwcnt]], dot[j])>=0 ) dwcnt--; f2[j][i] = f2[dw[dwcnt]][i] - mult(dot[i], dot[dw[dwcnt]], dot[j]); dw[++dwcnt] = j; } dw[1] = i; dwcnt = 1; for (j=i+1;j<=n;j++) if (dot[i].y<=dot[j].y) {dw[++dwcnt] = j; break;} for (j++;j<=n;j++) if (dot[i].y<=dot[j].y){ while (dwcnt>1 && mult(dot[dw[dwcnt-1]], dot[dw[dwcnt]], dot[j])<=0 ) dwcnt--; f2[i][j] = f2[i][dw[dwcnt]] + mult(dot[i], dot[dw[dwcnt]], dot[j]); dw[++dwcnt] = j; } } } int find_left(int a,int b,int c,int d){ int L = a, R = b, t=0; while (L<=R){ int mid = (L+R)>>1; if (query(a,mid,c,d)==0) L=mid+1; else R=mid-1, t=mid; } L = 0; R = ex[t].size()-1; int ret = 0; while (L<=R){ int mid = (L+R)>>1; if (dot[ex[t][mid]].y<ay[c]) L=mid+1; else ret=ex[t][mid], R=mid-1; } return ret; } int find_right(int a,int b,int c,int d){ int L = a, R = b, t=0; while (L<=R){ int mid = (L+R)>>1; if (query(mid,b,c,d)==0) R=mid-1; else L=mid+1, t=mid; } L = 0; R = ex[t].size()-1; int ret = 0; while (L<=R){ int mid = (L+R)>>1; if (dot[ex[t][mid]].y>ay[d]) R=mid-1; else ret=ex[t][mid], L=mid+1; } return ret; } int find_down(int a,int b,int c,int d){ int L = c, R = d, t=0; while (L<=R){ int mid = (L+R)>>1; if (query(a,b,c,mid)==0) L=mid+1; else R=mid-1, t=mid; } L = 0; R = ey[t].size()-1; int ret=0; while (L<=R){ int mid = (L+R)>>1; if (dot[ey[t][mid]].x<ax[a]) L=mid+1; else ret=ey[t][mid], R=mid-1; } return ret; } int find_up(int a,int b,int c,int d){ int L = c, R = d, t=0; while (L<=R){ int mid = (L+R)>>1; if (query(a,b,mid,d)==0) R=mid-1; else L=mid+1, t=mid; } L = 0; R = ey[t].size()-1; int ret=0; while (L<=R){ int mid = (L+R)>>1; if (dot[ey[t][mid]].x>ax[b]) R=mid-1; else ret=ey[t][mid], L=mid+1; } return ret; } int main(){ scanf("%d%d",&k,&n); for (i=1;i<=n;i++){ dot[i].read(); ax[i] = dot[i].x; ay[i] = dot[i].y; } sort(dot+1,dot+n+1); sort(ax+1,ax+n+1); nx = unique(ax+1,ax+n+1)-ax-1; sort(ay+1,ay+n+1); ny = unique(ay+1,ay+n+1)-ay-1; for (i=1;i<=n;i++){ tx = lower_bound(ax+1,ax+nx+1,dot[i].x)-ax; ty = lower_bound(ay+1,ay+ny+1,dot[i].y)-ay; ex[tx].push_back(i); ey[ty].push_back(i); sum[tx][ty]++; } for (i=1;i<=nx;i++) for (j=1;j<=ny;j++) sum[i][j] += sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1]; init(); scanf("%d",&Q); while (Q--){ scanf("%d%d%d%d",&a,&b,&c,&d); a = lower_bound(ax+1,ax+nx+1,a)-ax; b = upper_bound(ax+1,ax+nx+1,b)-ax-1; c = lower_bound(ay+1,ay+ny+1,c)-ay; d = upper_bound(ay+1,ay+ny+1,d)-ay-1; //printf("%d %d %d %d\n",a,b,c,d); if (query(a,b,c,d)<3) {printf("0\n");continue;} if (a>=b || c>=d) {printf("0\n");continue;} A = find_left(a,b,c,d); B = find_right(a,b,c,d); C = find_down(a,b,c,d); D = find_up(a,b,c,d); //printf("%d %d %d %d\n",A,B,C,D); if (A==B || C==D) {printf("0\n");continue;} ans = f1[A][D] + f1[D][B] + f2[A][C] +f2[C][B]; ans += mult(dot[A], dot[C], dot[D]) + mult(dot[D], dot[C], dot[B]); printf("%.1lf\n",(double)ans/2.); } return 0; }