war
反过来求向量 v v v使得第二个凸包 B B B移动后与第一个凸包 A A A相交
即 ∃ a ∈ A , b ∈ B , b + v = a → v = a − b \exists a\in A,b\in B,b+v=a\to v=a-b ∃a∈A,b∈B,b+v=a→v=a−b
求出闽科夫斯基和 C = { A + ( − B ) } C=\{A+(-B)\} C={A+(−B)}(将 B B B中点坐标全部取反)
判断向量 v v v是否在 C C C内即可
#include<bits/stdc++.h>
typedef double db;
typedef long long ll;
const int N=2e5+10;
using namespace std;
int q;
inline char gc()
{
static char buf[(1<<15)];static int p1=0,p2=0;
if(p1==p2) p1=0,p2=fread(buf,1,(1<<15),stdin);
return (p1==p2)?EOF:buf[p1++];
}
char cp;
inline void rd(int &x)
{
cp=gc();x=0;int f=0;
for(;!isdigit(cp);cp=gc()) if(cp=='-') f=1;
for(;isdigit(cp);cp=gc()) x=x*10+(cp^48);
if(f) x=-x;
}
struct P{
int x,y;
P(int x_=0,int y_=0):x(x_),y(y_){};
P operator +(const P&ky){return P(x+ky.x,y+ky.y);}
P operator -(const P&ky){return P(x-ky.x,y-ky.y);}
ll operator ^(const P&ky){return (ll)x*ky.y-(ll)y*ky.x;}
inline ll len(){return (ll)x*x+(ll)y*y;}
}stk[N],st,nw;
int top;
inline bool cmp(P a,P b)
{
if(a.x!=b.x) return a.x<b.x;
return a.y<b.y;
}
inline bool cmq(P a,P b){
ll dlt=(a-st)^(b-st);
if(dlt!=0) return dlt>0;
return (a-st).len()<(b-st).len();
}
inline bool onlf(P a,P b,P c,P d){return ((b-a)^(d-c))>=0;}
struct convx{
int n;
P p[N],v[N];
inline void graham()
{
int i;
for(i=2;i<=n;++i) if(cmp(p[i],p[1])) swap(p[1],p[i]);
st=p[1];sort(p+2,p+n+1,cmq);stk[1]=p[1];stk[2]=p[2];top=2;
for(i=3;i<=n;++i){
for(;top>1 && onlf(stk[top],p[i],stk[top-1],stk[top]);top--);
stk[++top]=p[i];
}
for(i=1;i<=top;++i) p[i]=stk[i];n=top;
for(i=1;i<n;++i) v[i]=p[i+1]-p[i];v[n]=p[1]-p[n];
}
}A,B,C;
inline void Minkowski()
{
int i,j;int &k=C.n;
k=1;C.p[1]=A.p[1]+B.p[1];
for(i=j=1;i<=A.n || j<=B.n;){
k++;
if(j>B.n || (i<=A.n && (A.v[i]^B.v[j])>=0))
C.p[k]=C.p[k-1]+A.v[i++];
else C.p[k]=C.p[k-1]+B.v[j++];
}
}
inline bool in(P o)
{
if(((o-st)^(C.p[2]-st))>0 || ((C.p[C.n]-st)^(o-st))>0) return false;
int pos=lower_bound(C.p+1,C.p+C.n+1,o,cmq)-C.p-1;
return (C.v[pos]^(o-C.p[pos]))>=0;
}
int main(){
freopen("war.in","r",stdin);
freopen("war.out","w",stdout);
int i,x,y;
rd(A.n);rd(B.n);rd(q);
for(i=A.n;i>0;--i){rd(x);rd(y);A.p[i]=P(x,y);}
for(i=B.n;i>0;--i){rd(x);rd(y);B.p[i]=P(-x,-y);}
A.graham();B.graham();
Minkowski();C.graham();
st=C.p[1];
for(;q;--q){
rd(x);rd(y);nw=P(x,y);
putchar(in(nw)?'1':'0');
putchar('\n');
}
fclose(stdin);fclose(stdout);
return 0;
}
robot
九老师的计数题。。。
从 ( i , j ) (i,j) (i,j)向下走相当于 i → ( i % n + 1 ) i\to (i\% n+1) i→(i%n+1),向右走相当于 j → ( j % m + 1 ) j\to (j\%m+1) j→(j%m+1)
结论1:
每条左下-右上对角线格子走的方向相同。
考虑若在某个格子向下走,则它右侧相邻的格子必然由它上面的格子向下走得到。
结论2:
对于
n
×
n
n\times n
n×n的矩阵,每条对角线上格子相等。
那么对于
n
×
m
(
n
≠
m
)
n\times m(n\neq m)
n×m(n̸=m)的矩阵,设
d
=
gcd
(
n
,
m
)
d=\gcd(n,m)
d=gcd(n,m),将矩阵划分成若干个
d
×
d
d\times d
d×d的矩阵,则小矩阵内部对角线上格子相等,且每个小矩阵形态相同。
考虑用
n
×
m
n\times m
n×m的矩阵拼成一个边长为
l
c
m
(
n
,
m
)
lcm(n,m)
lcm(n,m)的方阵,显然每条对角线格子是相等的:
从行来看,第
i
i
i条对角线和第
i
+
n
i+n
i+n条相等;从列来看,第
i
i
i条对角线和第
i
+
m
i+m
i+m条相等。
所以第
i
i
i条对角线和第
i
+
gcd
(
n
,
m
)
i+\gcd(n,m)
i+gcd(n,m)条对角线相等。
结论3:
若在每个 d × d d\times d d×d的矩阵中,向下走了 x x x格,向右走了 y y y格( x + y = d x+y=d x+y=d),则 gcd ( x , y ) = 1 , gcd ( x , n ) = 1 , gcd ( y , m ) = 1 \gcd(x,y)=1,\gcd(x,n)=1,\gcd(y,m)=1 gcd(x,y)=1,gcd(x,n)=1,gcd(y,m)=1。
走 l c m ( x , n ) x \dfrac{lcm(x,n)}{x} xlcm(x,n)轮后回到第一行,走 l c m ( y , m ) y \dfrac{lcm(y,m)}{y} ylcm(y,m)后回到第一列,要求只在最后一步 ( n × m ) (n\times m) (n×m)时恰好第一次回到 ( 1 , 1 ) (1,1) (1,1),即:
l c m ( l c m ( x , n ) x , l c m ( y , m ) y ) = n m gcd ( n , m ) lcm(\dfrac{lcm(x,n)}{x},\dfrac{lcm(y,m)}{y})=\dfrac{nm}{\gcd(n,m)} lcm(xlcm(x,n),ylcm(y,m))=gcd(n,m)nm
通过 l c m ( a , b ) a = b gcd ( a , b ) , l c m ( a , b ) = a b gcd ( a , b ) \dfrac{lcm(a,b)}{a}=\dfrac{b}{\gcd(a,b)},lcm(a,b)=\dfrac{ab}{\gcd(a,b)} alcm(a,b)=gcd(a,b)b,lcm(a,b)=gcd(a,b)ab这两种变换可以得到:
gcd ( gcd ( x , n ) , gcd ( y , m ) ) = gcd ( x , n ) gcd ( y , m ) \gcd(\gcd(x,n),\gcd(y,m))=\gcd(x,n)\gcd(y,m) gcd(gcd(x,n),gcd(y,m))=gcd(x,n)gcd(y,m)
当且仅当 gcd ( x , y ) = 1 , gcd ( x , n ) = 1 , gcd ( y , m ) = 1 \gcd(x,y)=1,\gcd(x,n)=1,\gcd(y,m)=1 gcd(x,y)=1,gcd(x,n)=1,gcd(y,m)=1时等式成立。
DP:
发现若在第一个小矩阵中走到了
(
i
,
j
)
(i,j)
(i,j),则在后面的小矩阵中必然都走到了
(
(
i
+
k
d
−
1
)
%
n
+
1
,
(
j
+
k
d
−
1
)
%
m
+
1
)
((i+kd-1)\%n+1,(j+kd-1)\%m+1)
((i+kd−1)%n+1,(j+kd−1)%m+1),所以可以
O
(
d
n
m
)
O(dnm)
O(dnm)求出
d
r
[
i
]
[
j
]
dr[i][j]
dr[i][j]表示第一轮经过
(
i
,
j
)
(i,j)
(i,j)时最多可以经过多少个格子(考虑每轮是否到达障碍格)。
设 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示第一轮到达 ( i , j ) (i,j) (i,j)最多能经过 k k k个格子的方案数,转移 O ( 1 ) O(1) O(1)。
#include<bits/stdc++.h>
#define gc getchar
using namespace std;
const int N=52,mod=998244353;
typedef long long ll;
int tk,n,m,d,ans,f[N][N][N*N],dr[N][N];
char s[N][N];
inline int gcd(int x,int y){return (!y)?x:gcd(y,x%y);}
inline void dn(int &x,int y){if(y<x) x=y;}
inline void ad(int &x,int y){x+=y;if(x>=mod) x-=mod;}
int main(){
freopen("robot.in","r",stdin);
freopen("robot.out","w",stdout);
int i,j,x,y,k,ix,iy,w,rnd,lim;
for(scanf("%d",&tk);tk;--tk){
scanf("%d%d",&n,&m);d=gcd(n,m);ans=0;lim=n*m;rnd=lim/d;
for(i=1;i<=n;++i){
scanf("%s",s[i]+1);
for(j=1;j<=m;++j) s[i][j]-='0';
}
for(x=0;x<=d;++x){
y=d-x;
if((x==0 && n>1) || (y==0 && m>1)) continue;
if(x>0 && y>0 && ((gcd(x,y)!=1) || (gcd(y,m)!=1) || (gcd(x,n)!=1))) continue;
for(i=1;i<=x+1;++i)
for(j=1;j<=y+1;++j){
ix=i;iy=j;w=i+j-2;dr[i][j]=lim;
for(k=0;k<rnd;++k){
if(s[ix][iy])
{dn(dr[i][j],w);break;}
ix+=x;iy+=y;w+=d;
if(ix>n) ix-=n;if(iy>m) iy-=m;
}
}
memset(f,0,sizeof(f));f[1][1][dr[1][1]]=1;
for(i=1;i<=x+1;++i)
for(j=1;j<=y+1;++j)
for(k=1;k<=lim;++k){
if(i<=x) ad(f[i+1][j][min(k,dr[i+1][j])],f[i][j][k]);
if(j<=y) ad(f[i][j+1][min(k,dr[i][j+1])],f[i][j][k]);
}
for(k=1;k<=lim;++k) ad(ans,(ll)f[x+1][y+1][k]*k%mod);
}
printf("%d\n",ans);
}
fclose(stdin);fclose(stdout);
return 0;
}
line
k , k + 1 , . . . , k + r − l + 1 k,k+1,...,k+r-l+1 k,k+1,...,k+r−l+1是连续的!
主席树上二分即可(前段后段绝对值拆开分别为负/正)
离散化还会TLE…(sort+lower_bound的常数。。。)
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
using namespace std;
const int N=1e6+10,mx=1e6;
typedef long long ll;
int n,m,a[N],cnt;
int rt[N],ls[N*22],rs[N*22];
ll qz[N],ans;
struct P{ll ss;int gs;}t[N*22],tp;
inline char gc()
{
static char buf[(1<<15)];static int p1=0,p2=0;
if(p1==p2) p1=0,p2=fread(buf,1,(1<<15),stdin);
return (p1==p2)?EOF:buf[p1++];
}
char cp;
inline void rd(int &x)
{
cp=gc();x=0;int f=0;
for(;!isdigit(cp);cp=gc()) if(cp=='-') f=1;
for(;isdigit(cp);cp=gc()) x=x*10+(cp^48);
if(f) x=-x;
}
template<class T>inline void prit(T x)
{if(x>9) prit(x/10);putchar('0'+(x%10));}
void ins(int pre,int &nw,int l,int r,int pos)
{
nw=++cnt;ls[nw]=ls[pre];rs[nw]=rs[pre];
t[nw].gs=t[pre].gs+1;t[nw].ss=t[pre].ss+pos;
if(l==r) return;
if(pos<=mid) ins(ls[pre],ls[nw],l,mid,pos);
else ins(rs[pre],rs[nw],mid+1,r,pos);
}
void ask(int pre,int nw,int l,int r,int pos)
{
if(t[nw].gs==t[pre].gs) return;
if(l==r){
if(pos+tp.gs>=l) tp.gs++,tp.ss+=(t[nw].ss-t[pre].ss);
return;
}
if(mid<pos+tp.gs+(t[ls[nw]].gs-t[ls[pre]].gs)){
tp.gs+=(t[ls[nw]].gs-t[ls[pre]].gs);
tp.ss+=(t[ls[nw]].ss-t[ls[pre]].ss);
ask(rs[pre],rs[nw],mid+1,r,pos);
}else ask(ls[pre],ls[nw],l,mid,pos);
}
int main(){
freopen("line.in","r",stdin);
freopen("line.out","w",stdout);
int i,x,y,z,len;rd(n);rd(m);qz[0]=0LL;
for(i=1;i<=n;++i) {rd(a[i]);qz[i]=qz[i-1]+a[i];}
for(i=1;i<=n;++i){
ins(rt[i-1],rt[i],1,mx,a[i]);
}
for(i=1;i<=m;++i){
rd(x);rd(y);rd(z);tp.gs=0;tp.ss=0LL;len=y-x+1;ans=0;
ask(rt[x-1],rt[y],1,mx,z);
if(tp.gs) ans+=((ll)((z<<1)+tp.gs-1)*tp.gs/2-tp.ss);
if(tp.gs<len) ans+=(qz[y]-qz[x-1]-tp.ss-((z<<1)+tp.gs+len-1)*(ll)(len-tp.gs)/2);
prit(ans);putchar('\n');
}
return 0;
}
总结
T3比较傻,但我傻到总是发现不了傻题。。。
T1大胆创造闽科夫斯基和,T2大胆找规律
加起来能有200分?