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;
}
T2、
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;
}
T3、
压轴神题
思路很好
只要我们知道长方形内最高点,最低点,最左点和最右点,预处理这些点之间的上下凸壳就可以合并求答案了。
找最点可以用二分查找矩形内是否有点在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;
}