Codeforces Beta Round #13 题解

786 阅读4分钟

比赛链接

B

思路

计算几何题。首先确定合法情况下必定只有五个不同的端点,可以用set维护这个特性。在此基础上,找到拥有共同端点的两条线,也就是字母‘A’的腰,求出他们的长度,根据勾股定理确定他们的夹角是否合法。

对于第三条边,假如我们要判断其端点C是否在AB上,可以用AC和BC的斜率是否相等以及纵坐标是否同号(因为要考虑C在AB延长线上的情况)来判断,在此过程中还可以顺便求出短边与长边的长度比,将其塞到一个check函数中方便日后调用。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef long double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void say() {}
void say_() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
    int __=0;
    _=0;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            __=1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        _=_*10+ch-48;
        ch=getchar();
    }
    _=__?-_:_;
    read(oth...);
}
template <typename T>
void Out(T _)
{
    if(_<0)
    {
        putchar('-');
        _=-_;
    }
    if(_>=10)
       Out(_/10);
    putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void say(T _, T2... oth)
{
	Out(_);
	putchar('\n');
	say(oth...);
}
template <typename T, typename... T2>
inline void say_(T _, T2... oth)
{
	Out(_);
	putchar(' ');
	say_(oth...);
}
/*#################################*/
ll cnt;
db eps=0.25;
pii a[10];
set<pii> had;
struct seg
{
	ll x1,y1,x2,y2,len;
	void print()
	{
		say_(x1,y1,x2,y2,len);
		puts("");
	}
}b[5];
ll G_dis(ll x1,ll y1,ll x2,ll y2)
{
	return pow(x1-x2,2)+pow(y1-y2,2);
}
pii check(ll x1,ll y1,ll x2,ll y2,ll x3,ll y3)
{
	// say_(x1,y1,x2,y2,x3,y3);
	// puts("");
	pii ret=make_pair(-1,-1);
	if(x1==x3 || x2==x3)
	{
		if(x1==x3 && x2==x3 && db(min(abs(y1-y3),abs(y2-y3)))/db(max(abs(y1-y3),abs(y2-y3)))>=0.25)
			ret=make_pair(1,1);
		return ret;
	}
	db k1=db((y1-y3))/db((x1-x3)),k2=db((y2-y3))/db((x2-x3));
	// cout<<k1<<"?????"<<k2<<endl;
	if(k1!=k2 || (y1-y3)*(y2-y3)>=0)
		return ret;
	db first=sqrt(min(G_dis(x1,y1,x3,y3),G_dis(x2,y2,x3,y3)));
	db second=sqrt(max(G_dis(x1,y1,x3,y3),G_dis(x2,y2,x3,y3)));
	// printf("%.0Lf %.0Lf %.4Lf\n",first,second,first/second);
	if(first/second<eps)
		return ret=make_pair(-1,-1);
	else
		return ret=make_pair(first,second);
}
void solve()
{
	++cnt;
	had.clear();
	ll p;
	rep(i,1,6)
	{
		read(a[i].first,a[i].second);
		if(had.find(a[i])!=had.end())
			p=i;
		had.insert(a[i]);
	}
	rep(i,2,6)
	{
		a[i].first-=a[1].first;
		a[i].second-=a[1].second;
	}
	a[1].first=0;
	a[1].second=0;
	// rep(i,1,6)
	// {
		// say_(a[i].first,a[i].second);
		// puts("");
	// }
	// if(cnt==35)
	// {
		// rep(i,1,6)
		// {
			// say_(a[i].first,a[i].second);
			// puts("");
		// }
	// }
	if(had.size()!=5)
	{
		puts("NO");
		return;
	}
	ll sum=0;
	seg fir,sec,thr;
	fir.x1=LLm;
	rep(i,1,3)
	{
		ll tmp=i<<1;
		b[i]=seg({a[tmp-1].first,a[tmp-1].second,a[tmp].first,a[tmp].second});
		b[i].len=G_dis(b[i].x1,b[i].y1,b[i].x2,b[i].y2);
		if(a[tmp]!=a[p] && a[tmp-1]!=a[p])
		{
			thr=b[i];
		}
		else
		{
			if(fir.x1!=LLm)
				sec=b[i];
			else
				fir=b[i];
			sum+=b[i].len;
		}
	}
	pii tmpa,tmpb;
	if(make_pair(fir.x1,fir.y1)!=a[p])
		tmpa=make_pair(fir.x1,fir.y1);
	else
		tmpa=make_pair(fir.x2,fir.y2);
	if(make_pair(sec.x1,sec.y1)!=a[p])
		tmpb=make_pair(sec.x1,sec.y1);
	else
		tmpb=make_pair(sec.x2,sec.y2);
	// say_(tmpa.first,tmpa.second,tmpb.first,tmpb.second);
	// puts("");
	// say(sum);
	// say(G_dis(23902806,17823588,0,0)+G_dis(23902806,17823588,-82089,59655591));
	// say(G_dis(tmpa.first,tmpa.second,tmpb.first,tmpb.second));
	if(sum<G_dis(tmpa.first,tmpa.second,tmpb.first,tmpb.second))
	{
		puts("NO");
		return;
	}
	// say(sum);
	// fir.print();
	// sec.print();
	// thr.print();
	// puts("::::::");
	// pii cur=check(fir.x1,fir.y1,fir.x2,fir.y2,thr.x1,thr.y1);
	// cout<<cur.first<<" [][][][][][]"<<cur.second<<endl;
	if(check(fir.x1,fir.y1,fir.x2,fir.y2,thr.x1,thr.y1).first==-1)
	{
		if(check(fir.x1,fir.y1,fir.x2,fir.y2,thr.x2,thr.y2).first==-1)
		{
			puts("NO");
			return;
		}
		if(check(sec.x1,sec.y1,sec.x2,sec.y2,thr.x1,thr.y1).first==-1)
		{
			// cout<<"???????"<<endl;
			puts("NO");
			return;
		}
		puts("YES");
		return;
	}
	// cout<<"::::::::::::"<<endl;
	// cur=check(sec.x1,sec.y1,sec.x2,sec.y2,thr.x1,thr.y1);
	// cout<<cur.first<<">>> "<<cur.second<<endl;
	// puts("::::::::::::::::::");
	if(check(sec.x1,sec.y1,sec.x2,sec.y2,thr.x2,thr.y2).first==-1)
	{
		puts("NO");
		return;
	}
	puts("YES");
}
int main()
{
	int _;
	cin>>_;
	while(_--)
	{
		solve();
	}
}

C

思路

dp题。在某个元素大小下降的位置,对于较小的元素,必然是将其变成左边的元素或者右边的元素。因此最终的序列中的元素必然在原序列中出现过。

设原序列排序后的得到的序列为bb,并设f[i][j]f[i][j]为当前ii个元素单调不下降,且a[i]<=b[j]a[i]<=b[j]时需要的最少步数。由前面的结论可以知道,a[i]=b[j]a[i]=b[j]a[i]<=b[j1](j>1)a[i]<=b[j-1](j>1),因此f[i][j]=min(f[i1][j]+abs(a[i]b[j]),f[i][j1])f[i][j]=min(f[i-1][j]+abs(a[i]-b[j]),f[i][j-1])。采用滚动数组优化可以压缩至一维空间。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void say() {}
void say_() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
    int __=0;
    _=0;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            __=1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        _=_*10+ch-48;
        ch=getchar();
    }
    _=__?-_:_;
    read(oth...);
}
template <typename T>
void Out(T _)
{
    if(_<0)
    {
        putchar('-');
        _=-_;
    }
    if(_>=10)
       Out(_/10);
    putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void say(T _, T2... oth)
{
	Out(_);
	putchar('\n');
	say(oth...);
}
template <typename T, typename... T2>
inline void say_(T _, T2... oth)
{
	Out(_);
	putchar(' ');
	say_(oth...);
}
/*#################################*/
const ll N=5005;
ll n;
ll a[N],b[N],f[N];
int main()
{
	read(n);
	rep(i,1,n)
	{
		read(a[i]);
		b[i]=a[i];
	}
	sort(b+1,b+n+1);
	rep(i,1,n)
	{
		rep(j,1,n)
		{
			f[j]+=abs(a[i]-b[j]);
			if(j>1)
				f[j]=min(f[j-1],f[j]);
		}
	}
	say(f[n]);
}

E

思路

暴力跳过去必然超时,因此要分块,一块一块地跳。

预处理出从第ii个点跳到其所在块结尾所需的步数以及其到达结尾时所处的位置,每次更新第xx个点时,xx后面点的信息必然不会受影响,因此只更新xx左边的同块的点,复杂度为O(n)O(\sqrt n)。询问时,直接一步跳到块中的最后一个点,再跳一步到下一个块,重复上述过程直到跳出界,复杂度也为O(n)O(\sqrt n)。因此总复杂度为O(nn)O(n\sqrt n)

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef int ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void say() {}
void say_() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
    int __=0;
    _=0;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            __=1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        _=_*10+ch-48;
        ch=getchar();
    }
    _=__?-_:_;
    read(oth...);
}
template <typename T>
void Out(T _)
{
    if(_<0)
    {
        putchar('-');
        _=-_;
    }
    if(_>=10)
       Out(_/10);
    putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void say(T _, T2... oth)
{
	Out(_);
	putchar('\n');
	say(oth...);
}
template <typename T, typename... T2>
inline void say_(T _, T2... oth)
{
	Out(_);
	putchar(' ');
	say_(oth...);
}
/*#################################*/
const ll N=1E5+10;
ll n,m,unit;
ll a[N],lst[N],cnt[N],block[N];
void print()
{
	rep(i,1,n)
		say_(lst[i]);
	puts("");
	rep(i,1,n)
		say_(cnt[i]);
	puts("");
}
void update(ll x,ll val)
{
	a[x]=val;
	for(int i=x;block[i]==block[x];--i)
	{
		ll nxt=i+a[i];
		if(block[i]!=block[nxt])
		{
			cnt[i]=0;
			lst[i]=i;
			continue;
		}
		cnt[i]=cnt[nxt]+1;
		lst[i]=lst[nxt];
	}
}
void query(ll x)
{
	ll cur=x,tot=1;
	while(cur<=n)
	{
		tot+=cnt[cur];
		cur=lst[cur];
		if(cur+a[cur]<=n)
		{
			cur+=a[cur];
			++tot;
		}
		else
			break;
	}
	printf("%d %d\n",cur,tot);
}
int main()
{
	read(n,m);
	unit=ceil(sqrt(n));
	rep(i,1,n)
		block[i]=(i-1)/unit+1;
	rep(i,1,n)
		read(a[i]);
	for(int i=n;i>=1;--i)
	{
		ll nxt=i+a[i];
		if(block[i]!=block[nxt])
		{
			lst[i]=i;
			continue;
		}
		cnt[i]=cnt[nxt]+1;
		lst[i]=lst[nxt];
	}
	ll ty,x,y;
	// print();
	while(m--)
	{
		read(ty);
		if(ty==0)
		{
			read(x,y);
			update(x,y);
		}
		else
		{
			read(x);
			query(x);
		}
	}
	// print();
}