1. 程式人生 > >2018.12.08【NOIP提高組】模擬B組 JZOJ 3518 進化序列

2018.12.08【NOIP提高組】模擬B組 JZOJ 3518 進化序列

描述

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);
	}
}