2018.12.08【NOIP提高组】模拟B组 JZOJ 3518 进化序列

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/84894213

描述

A 1 , A 2 . . . A n 1 , A n A_1,A_2...A_{n-1},A_n n n 个基因

一个基因 A x A_x 可以进化为序列中在它之后的基因 A y ( x y ) A_y(x\leq y)
这个进化的复杂度,等于 A x   o r   A x + 1   o r A x + 2   o r . . . A y 1   o r   A y A_x\ or\ A_{x+1}\ or A_{x+2}\ or ...A_{y-1}\ or\ A_y 的值

求进化后值小于 M M 的方案数


思路

先扯淡

考试的时候就推出了 O ( n l o g a i ) O(nloga_i) 的优秀做法,真不知道写题解的人是怎么想的,竟然打线段树。。。开氧气后还比我快


正题

先把题解中的话引出来...
说实话我考场都A了还没看懂题解,写的什么鬼
个人做法:
我们发现若 x x 能合并到 y y 那么显然 x + 1 x+1 也能合并到 y y ,根据这个特性,我们用一个队列维护一端可以被合并的值,入队和出对操作的判断要用位运算
时间复杂度: O ( n l o g 2 a i ) O(nlog_2a_i)


暴力代码

#include<cstdio>
#include<cctype>
#include<algorithm>
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout)
#define r(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;int n,a[100001],yh[5001][5001],m,ans;
inline char Getchar()
{
    static char buf[100000],*p1=buf+100000,*pend=buf+100000;
    if(p1==pend)
	{
        p1=buf; pend=buf+fread(buf,1,100000,stdin);
        if (pend==p1) return -1;
    }
    return *p1++;
}
inline int read()
{
	char c;int d=1,f=0;
	while(c=Getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=Getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline void write(register long long x)
{
	if(x<0)write(45),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+48);
	return;
}
signed main()
{
	freopen("1.txt","r",stdin);
	freopen("jhxl.txt","w",stdout);
	n=read();m=read();
	r(i,1,n) yh[i][i]=a[i]=read();
	r(i,1,n-1) r(j,i+1,n) {yh[i][j]=yh[i][j-1]|a[j];if(yh[i][j]<m) ans++;}
	write(ans);
}

正解

#include<cstdio>
#include<cctype>
#include<algorithm>
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout)
#define r(i,a,b) for(register int i=a;i<=b;i++)
#define getk r(j,0,30) if(now[j]) k|=1<<j
using namespace std;int n,a[100001],m,head,now[32],k;
long long ans;
inline char Getchar()
{
    static char buf[100000],*p1=buf+100000,*pend=buf+100000;
    if(p1==pend)
	{
        p1=buf; pend=buf+fread(buf,1,100000,stdin);
        if (pend==p1) return -1;
    }
    return *p1++;
}
inline int read()
{
	char c;int d=1,f=0;
	while(c=Getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=Getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline void write(register long long x)
{
	if(x<0)write(45),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+48);
	return;
}
signed main()
{
	freopen("1.txt","r",stdin);
	freopen("jhxl2.txt","w",stdout);
	n=read();m=read();
	r(i,1,n) a[i]=read();
	r(i,0,30) if((a[1]>>i)&1) now[i]++;
	head=1;
	r(i,2,n)
	{
		r(j,0,30) if((a[i]>>j)&1) now[j]++;//放入对尾
		k=0;
		getk;
		while(k>=m&&head<i)//不满足要求剔除对头
		{
			r(j,0,30) if((a[head]>>j)&1) now[j]--;
			k=0;
			getk;
			head++;
		}
		ans+=i-head;//加上方案
	}
	write(ans);
}

Rand生成

#include<cstdlib>
#include<cstdio>
#include<ctime>
using namespace std;
signed main()
{
	freopen("1.txt","w",stdout);
	srand(time(0));
	printf("5000 %d\n",1+rand()%10000);
	for(register int i=1;i<=5000;i++) printf("%d ",1+rand()%10000);
}

d(对)p(拍)

#include<cstdlib>
#include<cstdio>
#include<ctime>
using namespace std;double t1,t2,t3;
signed main()
{
	for(register int i=1;i<1001;i++)
	{
		system("rand.exe");
		t1=clock();
		system("jhxl.exe");
		t2=clock();
		system("jhxl2.exe");
		t3=clock();
		if(system("fc jhxl.txt jhxl2.txt")) 
		{printf("测试点:#%3d 测试点信息:WA",i);return 0;}
		else printf("测试点:#%3d 测试点信息:AC n方用时:%0.3lfms nlogn用时:%0.3lfms\n",i,t2-t1,t3-t2);
	}
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/84894213