Codeforces Round #515 (Div. 3) 题解

141 阅读3分钟

比赛链接

A

思路

[1,l1][1,l-1]范围内有l1v\frac{l-1}{v}个。对于区间[r+1,n][r+1,n],找到最后一个小于rrvv的倍数,即r=nx×xr'=\lfloor \frac{n}{x}\rfloor\times x。答案是nrv\frac{n-r'}{v}

代码

#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 sf(a) scanf("%lld",&(a));
#define pf(a) printf("%lld\n",(a));
typedef long long ll;
using namespace std;
void solve()
{
	ll n,v,l,r;
	sf(n)sf(v)sf(l)sf(r)
	ll ans=(l-1)/v;
	ll tmp=r/v;
	r=tmp*v;
	cout<<r<<endl;
	ans+=(n-r)/v;
	pf(ans)
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
}

B

思路

考虑覆盖第ii个位置,如果有多种选择,那么选择最靠后的一个必然不会坏于其他的选择,因为这样可以在保证覆盖掉第ii个位置的前提下尽可能多地覆盖后面的点。定义两个指针分别指向当前未覆盖的最左边的点以及下一步要用的heater贪心即可。

代码

#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 sf(a) scanf("%lld",&(a));
#define pf(a) printf("%lld\n",(a));
typedef long long ll;
using namespace std;
const int N=1003;
ll n,r,m,ans,cnt,tot;
ll one[N],vis[N],d[N];
void print()
{
	rep(i,1,m)
		cout<<one[i]<<" ";
	cout<<endl;
}
int main()
{
	sf(n)sf(r)
	--r;
	rep(i,1,n)
	{
		ll tmp;
		sf(tmp)
		if(tmp==1)
			one[++m]=i;
	}
	int ind=1,cur=1;
	one[0]=0x3f3f3f3f;
	while(cur<=n)
	{
		int flag=0;
		rep(i,ind,m)
		{
			if(one[i]-r<=cur)
				flag=i;
		}
		if(flag)
		{
			++ans;
			cur=one[flag]+r+1;
			ind=flag+1;
		}
		else
		{
			ans=-1;
			break;
		}
	}
	pf(ans);
}

C

思路

相当于从第一个元素开始分别向左右延申出新的元素,记录每个元素与第一个元素的距离以及左右延申的最大距离,查询时O(1)O(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 sf(a) scanf("%lld",&(a));
#define pf(a) printf("%lld\n",(a));
typedef long long ll;
using namespace std;
const int N=2E5+10;
ll t,ldep,rdep;
ll dep[N],dir[N];
int main()
{
	sf(t)
	rep(i,1,t)
	{
		string ty;
		ll p;
		cin>>ty;
		sf(p)
		if(i==1)
			continue;
		if(ty[0]=='L')
		{
			dep[p]=++ldep;
		}
		else if(ty[0]=='R')
		{
			dep[p]=++rdep;
			dir[p]=1;
		}
		else
		{
			if(dir[p])
				pf(min(ldep+dep[p],rdep-dep[p]))
			else
				pf(min(rdep+dep[p],ldep-dep[p]))
		}
	}
}

D

思路

考虑去掉前ii个元素,那么使用的箱子数关于ii是不上升的。因此二分一个位置,将该位置之前的元素全部舍弃之后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 double db;
using namespace std;
const int N=2E5+10;
ll n,m,k;
ll a[N];
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
bool check(ll x)
{
	ll rem=m,cur=0;
	rep(i,x,n)
	{
		if(cur>=a[i])
			cur-=a[i];
		else if(rem)
		{
			cur=k-a[i];
			--rem;
		}
		else
			return 0;
	}
	return 1;
}
int main()
{
	In(3,&n,&m,&k);
	rep(i,1,n)
		In(1,a+i);
	ll l=1,r=n;
	while(l<r)
	{
		ll mid=(l+r)>>1;
		if(check(mid))
			r=mid;
		else
			l=mid+1;
	}
	Out(1,n-l+1);
}

E

思路

刚开始AABB是右端对齐的,因为BB会不断右移,所以对于BB中的任何一个11,都会与AA中位置在它右边的11对答案产生贡献。因此从右到左线性扫一遍,维护在AA遇到11的个数,在BB中遇到11维护答案即可。

代码

#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 sf(a) scanf("%lld",&(a));
#define pf(a) printf("%lld\n",(a));
typedef long long ll;
using namespace std;
const int M=998244353;
ll n,m,ans,sum;
string a,b;
ll ksm(ll x,ll k)
{
	ll ret=1;
	while(k)
	{
		if(k&1)
			ret*=x;
		ret%=M;
		x*=x;
		x%=M;
		k>>=1;
	}
	return ret;
}
int main()
{
	sf(n)sf(m)
	cin>>a>>b;
	reverse(a.begin(),a.end());
	reverse(b.begin(),b.end());
	a=' '+a;
	b=' '+b;
	rep(i,1,m)
	{
		if(i<=n && a[i]=='1')
			sum+=ksm(2,i-1);
		if(b[i]=='1')
			ans=(ans+sum)%M;
	}
	pf(ans)
}

F

思路

考虑只走一层的情况,最优必然是从左上角走到右下角或者反向走。因此先把每一层左上角的点与右下角的点之间的曼哈顿距离维护进答案。
现在考虑层之间的转移。走完一层之后的位置必然是该层的左上角或者右下角,转移时也必然是到下一层的左上角或右下角。设dp[i][0/1]dp[i][0/1]作为从起点开始到走完第ii层并且在第ii层的左上角(右下角)停止,需要花费的层之间转移的代价。显然这只关系到两层左上角和右下角的元素,要想最终位于第ii层的左上角,就要先从第i1i-1层的左上角或右下角转移到第ii层的右下角,反之同理。最后取min(dp[n][0],dp[n][1]min(dp[n][0],dp[n][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;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
	puts("");
}
ll max_(pii x)
{
	return max(x.first,x.second);
}
bool cmp_(const pii &x,const pii &y)
{
	if(max_(x)==max_(y))
	{
		if(x.first==y.first)
			return x.second>y.second;
		return x.first<y.first;
	}
	return max_(x)<max_(y);
}
ll M_dis(ll _,ll __,ll ___,ll ____)
{
	return abs(_-___)+abs(__-____);
}
const ll N=2E5+10;
pii da[N] ;
vector<pii> lev[N];
ll n,ans,cnt;
ll dp[N][2];
void print()
{
	rep(i,1,cnt)
		Out(1,lev[i].size());
		// Out_(2,dp[i][0],dp[i][1]);
}
int main()
{
	In(1,&n);
	rep(i,1,n)
		In(2,&da[i].first,&da[i].second);
	sort(da+1,da+n+1,cmp_);
	rep(i,1,n)
	{
		if(max_(da[i])!=max_(da[i-1]))
		{
			lev[cnt].push_back(da[i-1]);
			lev[++cnt].push_back(da[i]);
		}
		else
			ans+=M_dis(da[i].first,da[i].second,da[i-1].first,da[i-1].second);
	}
	if(max_(da[n])==max_(da[n-1]))
		lev[cnt].push_back(da[n]);
	rep(i,1,cnt)
		rep(j,0,1)
			dp[i][j]=LLM;
	dp[1][0]=lev[1].back().first+lev[1].back().second;
	dp[1][1]=lev[1].front().first+lev[1].front().second;
	ll dis00,dis01,dis10,dis11;
	rep(i,2,cnt)
	{
		dis00=M_dis(lev[i-1].front().first,lev[i-1].front().second,lev[i].front().first,lev[i].front().second);
		dis01=M_dis(lev[i-1].front().first,lev[i-1].front().second,lev[i].back().first,lev[i].back().second);
		dis10=M_dis(lev[i-1].back().first,lev[i-1].back().second,lev[i].front().first,lev[i].front().second);
		dis11=M_dis(lev[i-1].back().first,lev[i-1].back().second,lev[i].back().first,lev[i].back().second);
		dp[i][0]=min(dp[i-1][0]+dis01,dp[i-1][1]+dis11);
		dp[i][1]=min(dp[i-1][0]+dis00,dp[i-1][1]+dis10);
	}
	Out(1,ans+min(dp[cnt][0],dp[cnt][1]));
}