Icebound

icebound-area

std::bitset的神奇用法

今天在XJOJ爆了零 感觉很不爽
平常就知道bitset可以做很多事 这里做个整理

首先是floyd传递闭包啦
邻接矩阵是由一堆0和1组成的
然后如果满足了f[i][k] 那么 所有第k行为1的j都可以让f[i][j]=1
这样可以形象的写出一个N^2传递闭包

void floyd()
{
	for(int k=1;k<=n;k++)
	for(int i=1;i<=n;i++)
	if(f[i][k])
	f[i]|=f[k];
}

这个或运算在状压下完成 速度飞快

然后是XJOI的比赛题:
4维空间中有1个点集A,|A|=n,用(a,b,c,d)表示每个点。
共有m个询问,每次询问输入一个点(a,b,c,d),求最大的S,其中S={p|p∈A且ap<=a,bp<=b,cp<=c,dp<=d},输出|S|
数据范围<=30000 时限2s
这个看上去就很晕啊 我们必须要想办法降维
一个恶心的做法是排序降一维 树状数组降一维 用树套树再降两维?【我不会啊】
不过我们想一个暴力的做法
对于每个询问 离线处理 加入到数组中
对每一维按照这一维第一关键字 是否为询问为第二关键字(保证询问在后面)
然后我们可以维护一个01串 f[i]=0代表i这个点没有合适的询问对应 1代表有
然后每次遇到询问就统计01串中1的个数 加进去就好啦
这个正好可以使用bitset优化!!
神了!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
using namespace std;
const int N=31005;
bitset<N>s[N],t;
struct pos
{
    double x[4];
    int id,q;
}a[N*2];
int p,n,m;
bool cmp(pos a,pos b)
{
    if(a.x[p]==b.x[p])return a.id;//把id放到前面
    return a.x[p]<b.x[p];
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<4;j++)
        scanf("%lf",&a[i].x[j]);
        a[i].id=i;
    }
    scanf("%d",&m);
    for(int i=n+1;i<=n+m;i++)
    {
        for(int j=0;j<4;j++)
        scanf("%lf",&a[i].x[j]);
        a[i].q=i-n;
    }
    for(p=0;p<4;p++)
    {
        sort(a+1,a+n+m+1,cmp);t=0;
        for(int i=1;i<=n+m;i++)
        {
            if(a[i].q)
            {
                if(p!=0)s[a[i].q]&=t;
                else s[a[i].q]=t;
            }
            else
            t[a[i].id]=1;
        }
    }
    for(int i=1;i<=m;i++)printf("%d\n",s[i].count());
}

这个可以推广到多维的!!!

顺便附带一个bitset写的状压==简直思路清晰 妈妈再也不用担心我位运算写错啦

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
using namespace std;
const int N=1<<10;
int all[200],tot;
int ok[200][200];
int cnt[200];
bitset<20>tep,t1,t2;
int n,m;
void init()
{
	for(int i=0;i<(1<<n);i++)
	{
		tep=i;bool flag=1;
		for(int j=0;j<n;j++)
		if(tep[j]==1&&tep[j+1]==1){flag=0;break;}
		if(flag)
		all[++tot]=i,cnt[tot]=tep.count();
	}
	for(int i=1;i<=tot;i++)
	for(int j=1;j<=tot;j++)
	{
		t1=all[i],t2=all[j];
		bool flag=1;
		for(int k=0;k<n;k++)
		if(t1[k]==1)
		if(t2[k]||t2[k-1]||t2[k+1]){flag=0;break;}
		ok[i][j]=flag;
	}
}
long long f[15][200][100];
void dp()
{
	for(int i=1;i<=tot;i++)
	f[1][i][cnt[i]]=1;
 
	for(int i=1;i<n;i++)
	for(int j=1;j<=tot;j++)
	for(int k=0;k<=m;k++)
	{
		for(int s=1;s<=tot;s++)
		if(ok[j][s]&&k+cnt[s]<=m)f[i+1][s][k+cnt[s]]+=f[i][j][k];
	}
	long long ans=0;
	for(int i=1;i<=tot;i++)
	ans+=f[n][i][m];
	printf("%lld\n",ans);
}
int main()
{
	scanf("%d%d",&n,&m);
	init();
	dp();
}
  1. ww140142说道:

    什么鬼!
    什么恶心的做法啊显然我的是正解啊啊啊啊啊啊、
    再说了是树套树降两维而不是平衡树啊!
    咳lca已经写过高级数据结构的做法了少年你不来一发吗

    1. icebound说道:

      我蒟蒻 并不会高级数据结构== orz

      1. ww140142说道:

        不不不神犇带我学可持久化啊
        写完你也许会码力上升!
        Orz Icebound

        1. icebound说道:

          orz orz 蒟蒻icebound跪烂了

          1. lacclaude说道:

            神犇求带啥是纳什均衡

          2. icebound说道:

            神TM博弈

    1. icebound说道:

      orz