Codeforces Round #731 (Div. 3)(ABCDEFG)

A. Shortest Path with Obstacle

当两个点的x坐标或者y坐标相同的时候,需要多花2费绕开

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
void solve()
{
	int x1,y1,x2,y2,x3,y3;
	cin>>x1>>y1>>x2>>y2>>x3>>y3;
	int ans;
	if(x1==x2&&x2==x3&&y3<=max(y1,y2)&&y3>=min(y1,y2))ans=abs(y2-y1)+2;
	else if(y1==y2&&y2==y3&&x3<=max(x1,x2)&&x3>=min(x1,x2))ans=abs(x2-x1)+2;
	else ans=abs(x1-x2)+abs(y1-y2);
	cout<<ans<<endl;
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

B. Alphabetical Strings

某个字符数量大于1则无解,记录a的位置。若没有a的位置则无解。然后从a的位置用双指针l r,看看l-1或者r+1位置的字符是不是我们要的,是的话移动指针,依次判断每个字符,最后判断r-l+1是否是(最大字符-最小字符+1)即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
char s[N];
void solve()
{
	map<char,int>cnt;	
	cin>>s+1;
	int n=strlen(s+1),l=0,r=0;
	char ma='a';
	for(int i=1;i<=n;i++)
	{
		cnt[s[i]]++;
		if(s[i]=='a')l=r=i;
		ma=max(ma,s[i]);
	}
	for(auto i:cnt)
	{
		if(i.second>1||!l)
		{
			puts("no");
			return ;
		}
	}
	char now='b';
	while(now<=ma)
	{
		if(s[l-1]==now)l--;
		else if(s[r+1]==now)r++;
		now++;
	}
	if(r-l+1==ma-'a'+1)puts("yes");
	else puts("no");
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

C. Pair Programming

每次取出a,b数组中较小的数字即可。如果较小的取出来也不合法,那就无解。最后如果某个数组有剩余元素也记得取出来。用两个队列或者两个指针模拟即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;

int a[N],b[N];
void solve()
{
	int k,n,m;
	cin>>k>>n>>m;
	for(int i=1; i<=n; i++)cin>>a[i];
	for(int i=1; i<=m; i++)cin>>b[i];
	int i=1,j=1;
	vector<int>ans;
	bool f=1;
	while(i<=n&&j<=m)
	{
		if(k<min(a[i],b[j]))
		{
			f=0;
			break;
		}
		if(a[i]<b[j])
		{
			if(a[i]==0)k++;
			ans.push_back(a[i]);
			i++;
		}
		else
		{
			if(b[j]==0)k++;
			ans.push_back(b[j]);
			j++;
		}
	}
	while(i<=n)
	{
		if(k<a[i])
		{
			f=0;
			break;
		}
		if(a[i]==0)k++;
		ans.push_back(a[i]);
		i++;
	}
	while(j<=m)
	{
		if(k<b[j])
		{
			f=0;
			break;
		}
		if(b[j]==0)k++;
		ans.push_back(b[j]);
		j++;
	}
	if(f)
	{
		for(auto i:ans)printf("%d ",i);
		puts("");
	}
	else puts("-1");
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

D. Co-growing Sequence

首先确定b数组可以用递推的方式,先看第一个和第二个数,我肯定是对第二个数操作更好,因为这样字典序更小。所以b[1]=0。若要满足a[i-1]&a[i]=a[i-1],即让a[i]=a[i-1]|a[i],记录一下上一个a[i-1]^b[i-1]的值记做x。那么(x|a[i])^a[i]就是b[i]的值。^b[i]相当于补一些值给他。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N];
void solve()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	printf("0");
	int now;
	for(int i=2;i<=n;i++)
	{
		now=(a[i-1]|a[i])^a[i];
		printf(" %d",now);
		a[i]|=a[i-1];
	}
	puts("");
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

E. Air Conditioners(dp)

l[i]为只考虑i左侧所有空调对i的温度最小值。那么l[i]=min(l[i-1]+1,c)c为i这个点的空调温度,如果这个点没有空调c取无穷大即可,或者写个if判断一下。同理记录一个r[i]最后对每个点取min(l[i],r[i])就是答案

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10,inf=0x3f3f3f3f;
int l[N],r[N],a[N],b[N];
void solve()
{
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=k;i++)cin>>a[i];
	for(int i=1;i<=k;i++)cin>>b[i];
	map<int,int>m;
	for(int i=1;i<=k;i++)m[a[i]]=b[i];
	l[0]=inf,r[n+1]=inf;
	for(int i=1;i<=n;i++)
	{
		l[i]=l[i-1]+1;
		if(m[i])l[i]=min(l[i],m[i]);
	}
	for(int i=n;i>=1;i--)
	{
		r[i]=r[i+1]+1;
		if(m[i])r[i]=min(r[i],m[i]);
	}
	for(int i=1;i<=n;i++)printf("%d ",min(l[i],r[i]));
	puts("");
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

F. Array Stabilization (GCD version)(二分,线段树)

建立一颗线段树,维护l-r的gcd
将原来的数组复制一份到数组的尾巴。
二分操作次数k。然后检查是不是所有的i~i+k+1-1gcd都一样即可。

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10,inf=0x3f3f3f3f;
int w[N],n,q,k;
struct node
{
    int l,r;
    int v;
} tr[4*N];
inline void pushup(int u)
{
    tr[u].v=__gcd(tr[u<<1].v,tr[u<<1|1].v);
}
void build(int u,int l,int r)
{
    if(l==r)
    {
        tr[u]= {l,l,w[l]};
        return ;
    }
    tr[u]= {l,r};
    int mid=l+r>>1;
    build(u<<1,l,mid),build(u<<1|1,mid+1,r);
    pushup(u);
}
int query(int u,int l,int r)
{
    if(tr[u].l>=l&&tr[u].r<=r)return tr[u].v;
    int mid=tr[u].l+tr[u].r>>1;
    int v=0;
    if(l<=mid)v=query(u<<1,l,r);
    if(r>mid)v=__gcd(query(u<<1|1,l,r),v);
    return v;
}
bool check(int mid)
{
	mid++;
	int now=query(1,1,mid);
	for(int i=2;i+mid-1<=n;i++)
	{
		if(query(1,i,i+mid-1)!=now)return 0;
	}
	return 1;
}
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)scanf("%d",&w[i]),w[i+n]=w[i];
	n*=2;
	build(1,1,n);
	int l=0,r=1e6;
	while(l<r)
	{
		int mid=l+r>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	printf("%d\n",r);
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

G. How Many Paths? (tarjan缩点,拓扑排序,dp)

首先缩点,然后对强连通分量建图,在强连通分量上跑拓扑排序dp即可。
有几个坑点
1.注意自环要特判
2.假如某个点x存在自环。若1号点到不了x,那么x点的答案应该是0,而不是-1
3.强连通分量大小>1则这个分量里所有点距离设成无穷大
具体看代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e5+10,inf=0x3f3f3f3f;
int dfn[N],low[N],scc_cnt,id[N],Size[N],times,stk[N],top;
ll ans[N],res[N];
bool in[N],vis[N];
vector<int>g[N];
vector<int>G[N];
void tarjan(int u)
{
    dfn[u]=low[u]=++times;
    stk[++top]=u,in[u]=1;
    for(auto j:g[u])
    {
        if(!dfn[j])
        {
            tarjan(j);
            low[u]=min(low[u],low[j]);
        }
        else if(in[j])
            low[u]=min(low[u],dfn[j]);
    }
    if(dfn[u]==low[u])
    {
        int y;
        scc_cnt++;
        do
        {
            y=stk[top--];
            in[y]=0;
            id[y]=scc_cnt;
            Size[scc_cnt]++;
        }while(y!=u);
    }
}
void solve()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
    	res[i]=ans[i]=vis[i]=0;
    	g[i].clear();
    	G[i].clear();
    	times=scc_cnt=in[i]=dfn[i]=low[i]=Size[i]=stk[i]=id[i]=top=0;
	}
	unordered_map<int,int>ban;
    for(int i=1;i<=m;i++)
    {
        int u,v;
        cin>>u>>v;
        if(u!=v)g[u].push_back(v);
        else ban[u]=1;
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i);
    for(int i=1;i<=n;i++)
        for(auto j:g[i])
        {
            int a=id[i],b=id[j];
            if(a!=b)G[a].push_back(b);
        }
    ans[id[1]]=1;
    vis[id[1]]=1;
    for(auto i:ban)ans[id[i.first]]=-inf;
    for(int i=1;i<=n;i++)if(Size[id[i]]>1)ans[id[i]]=-inf;
    for(int i=id[1];i;i--)
        for(auto j:G[i])
        {
			ans[j]+=ans[i];
			if(vis[i])vis[j]=1;
			ans[j]=min(ans[j],2ll);
        }
    for(int i=1;i<=n;i++)
    {
    	if(!vis[id[i]])res[i]=0;
    	else if(ans[id[i]]<0)res[i]=-1;
    	else res[i]=ans[id[i]];
		printf("%lld ",res[i]);
	}
	puts("");
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}
/*
1
3 3
1 1
2 2
3 3 
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值