2017中国大学生程序设计竞赛-哈尔滨站

本文介绍了2017年中国大学生程序设计竞赛哈尔滨站的若干题目,包括A.Palindrome、B.K-th Number、C.Confliction等,并提供了详细的解题思路和代码实现。通过Manacher算法处理回文半径,二分搜索求解第k大数,以及几何问题的随机解决方案等,展示了算法在解决编程竞赛问题中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大力施工......(10/13)剩下的三个题好像不太能写啊?


A.Palindrome(hdu6230)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6230


首先用Manacher处理出所有的回文半径,然后可以得到每个点覆盖的范围,问题转换成了,有多少对点,满足,i能覆盖j而且j也能覆盖i,我们按照回文半径从大到小进行排序,然后用线段树进行维护,然后每次查询当前点能覆盖的范围有多少点即可,更新答案,最后将该点更新到线段树上。


代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=5e5+5;
char Ma[MAXN];
int Mp[MAXN];
void Manacher(int len)
{
	int l=len;
	Ma[0]='$';
	Ma[l]=0;
	int mx=0,id=0;
	for(int i=0;i<l;i++)
	{
		Mp[i]=mx>i?min(Mp[2*id-i],mx-i):1;
		while(Ma[i+Mp[i]]==Ma[i-Mp[i]])Mp[i]++;
		if(i+Mp[i]>mx)
		{
			mx=i+Mp[i];
			id=i;
		}
	}
}
struct node
{
	int id,r;
	node(int _id=0,int _r=0):id(_id),r(_r){}
	bool operator <(const node &a)const
	{
		return r>a.r;
	}
}sv[MAXN];
struct seg
{
	#define lson l,mid,rt<<1
	#define rson mid+1,r,rt<<1|1
	int sum[MAXN<<2];
	inline void push_up(int rt)
	{
		sum[rt]=sum[rt<<1]+sum[rt<<1|1];
	}
	void build(int l,int r,int rt)
	{
		sum[rt]=0;
		if(l==r)
			return ;
		int mid=(l+r)>>1;
		build(lson);
		build(rson);
	}
	void update(int pos,int val,int l,int r,int rt)
	{
		if(l==r)
		{
			sum[rt]=val;
			return ;
		}
		int mid=(l+r)>>1;
		if(pos<=mid)
			update(pos,val,lson);
		if(pos>mid)
			update(pos,val,rson);
		push_up(rt);
	}
	int query(int L,int R,int l,int r,int rt)
	{
		if(L<=l&&r<=R)
			return sum[rt];
		int ret=0;
		int mid=(l+r)>>1;
		if(L<=mid)
			ret+=query(L,R,lson);
		if(mid<R)
			ret+=query(L,R,rson);
		return ret;
	}
}se;
void solve()
{
	int len;
	ll ans=0;
	scanf("%s",Ma+1);
	len=strlen(Ma+1);
	Manacher(len+1);
	for(int i=1;i<=len;i++)
	{
		sv[i]=node(i,Mp[i]-1);
	}
	sort(sv+1,sv+1+len);
	se.build(1,len,1);
	for(int i=1;i<=len;i++)
	{
		int id=sv[i].id,r=sv[i].r;
		ans+=se.query(max(1,id-r),min(len,id+r),1,len,1);
		se.update(id,1,1,len,1);
	}
	printf("%lld\n",ans);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	int T;
	scanf("%d",&T);
	while(T--)
	{
		solve();
	}
	return 0;
}


B.K-th Number(hdu6231)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6231


二分答案,统计有多少个区间的第k大的值大于等于我们二分的答案,如果区间数大于m,就提高下界继续二分,否则降低上界。计数的时候可以采用双指针。


代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=1e5+5;
int a[MAXN],HASH[MAXN],tot,n,k;
ll m;
vector<int> sv;
int getid(int x)
{
	int ret=lower_bound(HASH+1,HASH+1+tot,x)-HASH;
	return ret;
}
bool judge(int mid)
{
	ll ret=0;
	sv.clear();
	sv.push_back(0);
	for(int i=1;i<=n;i++)
	{
		if(a[i]>=mid)
		{
			sv.push_back(i);
		}
	}
	for(int i=0;i<sv.size();i++)
	{
		if(i<k)
			continue;
		ret+=(sv[i-k+1]-sv[i-k])*(n-sv[i]+1);
	}
	return ret>=m;
}
void solve()
{
	tot=0;
	scanf("%d%d%lld",&n,&k,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		HASH[++tot]=a[i];
	}
	sort(HASH+1,HASH+1+tot);
	tot=unique(HASH+1,HASH+1+tot)-HASH-1;
	for(int i=1;i<=n;i++)
	{
		a[i]=getid(a[i]);
	}
	int l=1,r=tot;
	int ans=0;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(judge(mid))
		{
			l=mid+1;
			ans=mid;
		}
		else
		{
			r=mid-1;
		}
	}
	printf("%d\n",HASH[ans]);
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	int T;
	s
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值