2018.11.04 练习赛

T1 【NOIP2018模拟】动态点分治

题面:

题目描述
CJK 是一个喜欢数据结构的同学。一天他看到 BZOJ 4012 这一题。“这似乎可以用动态点分治做。”, 他想。然而他并不会动态点分治,因此他拿着这一题去问 XXX。
然而 XXX 跟他说:“你呀,毕竟图样图森破,上台拿衣服!连基础都没学好,就想学这些高端的东西! 来,我这里有一题,如果你能把这道题秒掉,我才能教你动态点分治!”
于是 CJK 打开题目。题目很短,只有一句话:
“给出 l, r, k,请从小到大输出所有在 [l, r] 范围内,能表示为 k 的非负整数次方的所有数。”
“多组数据。”,XXX 补充说,“注意所有数的 0 次方都为 1,因此 1 也得算进去哦。”

输入描述
第一行一个数 T,表示数据组数。
接下来 T 行,每行 3 个数 l,r,k,表示一组数据。

输出描述
对于每一组数据输出一行(总共输出 T 行)。
如果存在符合要求的数,则在一行内从小到大输出这些数;否则输出一个字符串 "None."(包括句点,不包括引号)。

输入样例
4
1 10 2
2 4 5
19562 31702689720 17701
3680 37745933600 10

输出样例
1 2 4 8
None.
313325401
10000 100000 1000000 10000000 100000000 1000000000 10000000000

备注
对于所有数据,T ≤ 10000,l ≤ r,0≤ l,r,k < 2^63。
子任务 1(20 分):r - l ≤ 1000。
子任务 2(30 分):l, r, k < 2^31。
子任务 3(50 分):l, r, k < 2^63。
这里的子任务表示的是数据类型,并不捆绑测试。
三个子任务中,各有 10 分的数据,满足 T = 10 且数据是随机的。
特别注意:本题中 0 的 0 次方也看做 1。

题解:

暴力枚举,上限为\(\frac{r}{k}\),这样可以防止爆掉\(long、 long\),注意特判\(0/1\)即可;

\(code\):

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<ctype.h>
#include<vector>
#define ld double
#define ls p<<1
#define rs p<<1|1
#define mid (l+r>>1)
#define ll long long
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc()
{
//	return getchar();
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
inline void read(T &x)
{
	char tt;
	bool flag=0;
	while(!isdigit(tt=gc())&&(tt!='-'));
	tt=='-'?(flag=1,x=0):(x=(tt^'0'));
	while(isdigit(tt=gc())) x=(x<<1)+(x<<3)+(tt^'0');
	if(flag) x=-x;
}

ll t,r,l,k;
int main()
{
	read(t);
	while(t--)
	{
		read(l),read(r),read(k);
		if(k==0)
		{
			if(l==0&&k==0)
			{if(r>=1) puts("0 1");
			if(r==0) puts("0");
			continue;}
			if(l==1&&k==0){puts("1");continue;}
			puts("None.");
			continue;
		}
		if(k==1)
		{
			if(r==0) {puts("None.");continue;}
			if(r>=1&&l<=1) {puts("1");continue;}
			if(l>1) {puts("None.");continue;}
			continue;
		}
		
		ll ans=1;bool flag=0;
		while(ans<=r/k)
		{
			if(ans>=l)
			printf("%lld ",ans),flag=1;
			ans*=k;
		}if(ans>=l&&ans<=r) printf("%lld",ans),flag=1;
		if(!flag) puts("None.");
		else puts("");
	}
}

T2【NOIP2018模拟】区间

题意:
给一数列,求最长区间满足其中\(a_i\)为整个区间公因数,卡\(O(NlogN)\)算法;

题解:

如果写出一个\(O(N^2)\)的算法,就容易往下想出正解了;

发现对于某一位置\(x\),向右扩展的最大长度如果小于\(x-1\)位置就没什么大的用处了,直接设\(F[i]\)\(i\)位置可以扩展的最大距离,然后用一只增不减的指针只要满足\(a[tail]%now==0\)就向前扫,扫完就记录\(F[i]=tail-1\);

对左边扫也是一样,最后取个最大值就行;

由于\(tail\)一直向前扫,数列中每个数只被遍历一次时间复杂度\(O(N)\);

\(code:\)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<ctype.h>
#include<vector>
#define ld double
#define ls p<<1
#define rs p<<1|1
#define mid (l+r>>1)
#define ll long long
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc()
{
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
inline void read(T &x)
{
	char tt;
	bool flag=0;
	while(!isdigit(tt=gc())&&(tt!='-'));
	tt=='-'?(flag=1,x=0):(x=(tt^'0'));
	while(isdigit(tt=gc())) x=(x<<1)+(x<<3)+(tt^'0');
	if(flag) x=-x;
}

const int maxn=4*(1e6)+2;
int n;
ll a[maxn],f[maxn];
int main()
{
//	freopen("B.in","r",stdin);
//	freopen("B.out","w",stdout);
	read(n);a[0]=-1;
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1,j=1;i<=n;i++)
	{
		while(j<=n&&a[j]%a[i]==0) j++;
		f[i]=j-1;
	}
//	for(int i=1;i<=n;i++)
//	printf("%lld ",f[i]);
	ll ans=0;
	for(int i=n,j=n;i>=1;i--)
	{
		while(j>=1&&a[j]%a[i]==0) j--;
		ans=max(ans,f[i]-j);
	}
	printf("%lld",ans);
}

T3 【NOIP2018模拟】灭虫

题意:

\(N\)个点,每个点可以选择向左覆盖\([p-l,p]\)的区间,向右覆盖\([r,p+r]\)的区间,问最大覆盖长度;

题解:

正解\(DP\)
设定一神仙状态\(F[i][j]\),表示讨论到第\(i\)个点,限制区间覆盖必须在离散化后的\(j\)坐标之前;

分两种情况转移:

1.若\(j\)小于\(p_i\)的位置,那么显然为了做出贡献,\(p_i\)会选择向左喷:

\(F[i][j]=max\{F[i-1][l_i]+pos[j]-pos[l_i]\}\),如图:

红色线段就是\(pos[j]-pos[l_i]\);

2.若\(j\)大于\(p_i\)的位置,那么\(p_i\)会选择向右喷;

同理可得:

\(code:\)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<ctype.h>
#include<vector>
#include<queue>
#define ld double
#define ls p<<1
#define rs p<<1|1
#define mid (l+r>>1)
#define ll long long
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc()
{
//	return getchar();
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
inline void read(T &x)
{
	char tt;
	bool flag=0;
	while(!isdigit(tt=gc())&&(tt!='-'));
	tt=='-'?(flag=1,x=0):(x=(tt^'0'));
	while(isdigit(tt=gc())) x=(x<<1)+(x<<3)+(tt^'0');
	if(flag) x=-x;
}

const int maxn=3002;
struct node{
	ll p,l,r;
	inline node(ll a=0,ll b=0,ll c=0)
	{p=a,l=b,r=c;}
	inline bool operator<(node a)const
	{return p<a.p;}
}a[maxn];

int n,tot;
int id[maxn*3];
ll hashh[maxn*3],f[2][maxn*3];
int main()
{
	read(n);
	for(int i=1;i<=n;i++)
	{
		ll x,y,z;
		read(x),read(y),read(z);
		a[i]=node(x,y,z);
		hashh[++tot]=x;
		hashh[++tot]=x-y;
		hashh[++tot]=x+z;
	}
	
	sort(hashh+1,hashh+1+tot);
	int m=unique(hashh+1,hashh+1+tot)-hashh-1;
	sort(a+1,a+1+n);
	for(int i=1;i<=n;i++)
	{
		a[i].l=lower_bound(hashh+1,hashh+1+m,a[i].p-a[i].l)-hashh;
		a[i].r=lower_bound(hashh+1,hashh+1+m,a[i].p+a[i].r)-hashh;
		a[i].p=lower_bound(hashh+1,hashh+1+m,a[i].p)-hashh;
		if(!id[a[i].p] or a[id[a[i].p]].l>a[i].l) id[a[i].p]=i;
	}
	
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		f[i&1][j]=f[(i-1)&1][j];
		
		for(int j=a[i].l+1;j<=a[i].p;j++)
		f[i&1][j]=max(f[i&1][j],f[(i-1)&1][a[i].l]+hashh[j]-hashh[a[i].l]);
		
		ll mx=f[(i-1)&1][a[i].p];
		for(int j=a[i].p+1;j<=a[i].r;j++)
		{
			f[i&1][j]=max(f[i&1][j],mx+hashh[j]-hashh[a[i].p]);
			if(id[j] and a[id[j]].l<a[i].p)
			mx=max(mx,f[(i-1)&1][a[id[j]].l]+hashh[a[i].p]-hashh[a[id[j]].l]);
		}
		for(int j=1;j<=m;j++)
		f[i&1][j]=max(f[i&1][j-1],f[i&1][j]);
	}
//	for(int i=1;i<=n;i++)
//	printf("%d ",f[i][3]);
	printf("%lld",f[n&1][m]);
}
posted @ 2018-11-04 18:48  Katoumegumi  阅读(87)  评论(0编辑  收藏  举报
返回顶部