我们假设每个位置被(d[i])个人选择了,并设(s[k]=(sumlimits_{i=1}^{k}d[i])-k)
找出最小的(k),可以证明如果从(k+1)开始讨论,所有精灵都不用跨过((k,k+1))寻找对手
然后就是贪心问题了,遍历到一个位置,把将要与其决斗的精灵插入(set)
然后再(set)中找第一个大于等于当前力量值的精灵
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
inline int read()
{
int x=0;char ch,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=0,ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int N=5e5+10,inf=0x3f3f3f3f;
int n,k,minn,sum,ret;
int head[N],cnt;
struct point
{
int nxt,to;
point(){}
point(const int &nxt,const int &to):nxt(nxt),to(to){}
}a[N<<1];
int p[N],b[N],c[N],d[N];
set<int> s;
set<int>::iterator it;
inline void link(int x,int y)
{
a[++cnt]=(point){head[x],y};head[x]=cnt;
}
inline void main()
{
n=read();minn=inf;
for(int i=1;i<=n;++i) p[i]=read(),++d[p[i]],link(p[i],i);
for(int i=1;i<=n;++i) b[i]=read();
for(int i=1;i<=n;++i) c[i]=read();
for(int i=1;i<=n;++i)
{
sum+=d[i];
if(minn>sum-i) minn=sum-i,k=i;
}
for(int i=1;i<=n;++i)
{
if(++k>n) k=1;
for(int e=head[k];e;e=a[e].nxt)
{
int t=a[e].to;
s.insert(c[t]);
}
if(b[k]>*--s.end()) s.erase(s.begin());
else it=s.lower_bound(b[k]),s.erase(it),++ret;
}
printf("%d
",ret);
}
}
signed main()
{
red::main();
return 0;
}
求严格上升子序列,我们可以把整个序列赋值一边翻转然后插在开头
(4 3 1 2 2 1 3 4)
求出这个序列的最长严格上升子序列长度和方案数,然后将方案数乘以(2^{n-maxlen-1})
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
inline int read()
{
int x=0;char ch,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=0,ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int N=5e5+10,mod=1e9+7,inf=0x3f3f3f3f;
int n;
int a[N],b[N];
int c[N],num;
int f[N],g[N],len[N];
struct node
{
int x,y;
}ans[N<<2];
inline node merge(node a,node b)
{
if(a.x==b.x) return(node){a.x,(a.y+b.y)%mod};
return a.x<b.x?b:a;
}
inline void update(int pos,int l,int r,int p,node k)
{
if(l==r)
{
ans[p]=merge(ans[p],k);
return;
}
if(pos<=mid) update(pos,l,mid,ls(p),k);
if(pos>mid) update(pos,mid+1,r,rs(p),k);
ans[p]=merge(ans[ls(p)],ans[rs(p)]);
}
inline node query(int pos,int l,int r,int p)
{
if(r<=pos) return ans[p];
if(mid<pos) return merge(query(pos,l,mid,ls(p)),query(pos,mid+1,r,rs(p)));
return query(pos,l,mid,ls(p));
}
inline void main()
{
n=read();
for(int i=1;i<=n;++i) a[i]=b[i]=read(),c[++num]=a[i];
sort(c+1,c+n+1);
num=unique(c+1,c+num+1)-c-1;
reverse(a+1,a+n+1);
for(int i=1;i<=n;++i) a[i+n]=b[i];
for(int i=1;i<=n*2;++i)
{
a[i]=lower_bound(c+1,c+num+1,a[i])-c+1;
node t=query(a[i]-1,1,n+1,1);
if(t.x==0) t=(node){1,1};
else ++t.x;
update(a[i],1,n+1,1,t);
}
node t=query(n+1,1,n+1,1);
printf("%d ",t.x);
for(int i=1;i<=n-t.x-1;++i) t.y=t.y*2%mod;
if(t.x==n) t.y=1;
printf("%d ",t.y);
}
}
signed main()
{
red::main();
return 0;
}
我们可以把苍蝇拍套在矩阵里,然后枚举左下角就可以枚举到全部位置
先用(bitset)把哪些位置有苍蝇标记出来,然后把苍蝇拍可以覆盖到的位置标记为(1)
然后枚举(x)轴和左下角,判断是否会拍到苍蝇
#include<bits/stdc++.h>
using namespace std;
namespace red{
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define mid ((l+r)>>1)
#define lowbit(i) ((i)&(-i))
inline int read()
{
int x=0;char ch,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=0,ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int N=510,M=1e5+10,mod=1e9+7,inf=0x3f3f3f3f;
int n,m,k,top,minx=inf,miny=inf,maxx=-inf,maxy=-inf;
int ret;
struct node
{
int x,y;
}p[M],nfly,a,b;
bitset<N> pfly[N],fly[N],now;
double st[N];
bool ans[N][N];
inline void main()
{
n=read(),m=read(),k=read();
for(int i=1;i<=k;++i)
nfly.x=read(),nfly.y=read(),fly[nfly.x].set(nfly.y);
k=read();
for(int i=1;i<=k;++i)
{
p[i].x=read(),p[i].y=read();
minx=min(minx,p[i].x);
miny=min(miny,p[i].y);
maxx=max(maxx,p[i].x);
maxy=max(maxy,p[i].y);
}
maxx-=minx,maxy-=miny;
for(int i=1;i<=k;++i)
p[i].x-=minx,p[i].y-=miny,pfly[p[i].x].set(p[i].y);
for(int x=0;x<=maxx;++x)//把苍蝇拍的覆盖到的点标记为1
{
top=0;
for(int i=1;i<=k;++i)
{
a=p[i],b=p[i==k?1:i+1];
if(a.y>b.y) swap(a,b);
if((a.x<x&&b.x<x)||(a.x>x&&b.x>x)||(a.x==x&&b.x>x)||(b.x==x&&a.x>x)) continue;
if(a.x==x&&b.x==x)
{
for(int y=a.y+1;y<=b.y-1;++y) pfly[x].set(y);
continue;
}
double k=1.0*(b.y-a.y)/(b.x-a.x);
st[++top]=k*(x-a.x)+a.y;
}
sort(st+1,st+top+1);
for(int y=0,flag=0,i=1;y<=maxy;++y)
{
while(i<=top&&st[i]<y) ++i,flag^=1;
if(flag||(i<=top&&st[i]==y)) pfly[x].set(y);
}
}
for(int i=0;i<=maxx;++i)
{
for(int y=0;y<=m-maxy;++y)
{
now=pfly[i]<<y;
for(int x=0;x<=n-maxx;++x)
{
if(!ans[x][y]&&(now&fly[x+i]).any())//在哪些点下手会拍到苍蝇
ans[x][y]=1;
}
}
}
for(int x=0;x<=n-maxx;++x)
{
for(int y=0;y<=m-maxy;++y)
{
ret+=!ans[x][y];
}
}
printf("%d
",ret);
}
}
signed main()
{
red::main();
return 0;
}