Codeforces Round #789 (Div. 2) 题解

61 阅读5分钟

比赛链接

A

思路

如果有00,直接用00与每个非00操作一次就行,没有的话就凑两个相同的数。

代码

#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 en puts("")
#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 OP() {}
void op() {}
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 OP(T _, T2... oth)
{
	Out(_);
	putchar('\n');
	OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
	Out(_);
	putchar(' ');
	op(oth...);
}
/*#################################*/
const ll N=105;
ll n;
ll a[N];
void solve()
{
	read(n);
	ll ans=0,flag=0;
	rep(i,1,n)
	{
		read(a[i]);
		if(a[i]==0)
			flag=1;
	}
	sort(a+1,a+n+1);
	if(flag)
	{
		ll ans=0;
		rep(i,1,n)
		{
			if(a[i]!=0)
				++ans;
		}
		OP(ans);
		return;
	}
	rep(i,1,n-1)
	{
		if(a[i]==a[i+1])
		{
			OP(n);
			return;
		}
	}
	OP(n+1);
}
int main()
{
	int _;
	cin>>_;
	while(_--)
	{
		solve();
	}
}

B1,B2

思路

把原串中数字每两个分为一组,如果一组中数字不同,说明需要进行一次操作变成00001111,要让最终连续段数目最少,就把它变成前后任意方向上第一个连续00001111

代码(B2)

#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 en puts("")
#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 OP() {}
void op() {}
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 OP(T _, T2... oth)
{
	Out(_);
	putchar('\n');
	OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
	Out(_);
	putchar(' ');
	op(oth...);
}
/*#################################*/
void solve()
{
	ll n;
	string s;
	read(n);
	cin>>s;
	s=' '+s;
	ll rec=-1;
	for(int i=1;i<=n;i+=2)
	{
		if(s[i]==s[i+1])
		{
			rec=i;
			break;
		}
	}
	if(rec==-1)
	{
		op(n/2,1);
		return;
	}
	ll ans1=rec/2,ans2=1;
	ll flag=s[rec]-'0';
	for(int i=rec+2;i<=n;i+=2)
	{
		if(s[i]!=s[i+1])
			++ans1;
		else
		{
			if(s[i]-'0'==flag)
			;
			else
			{
				++ans2;
				flag^=1;
			}
		}
	}
	op(ans1,ans2);en;
}
int main()
{
	int _;
	cin>>_;
	while(_--)
	{
		solve();
	}
}

C

思路

枚举a,ca,c,记fi,jf_{i,j}为在第jj个数后面有多少比第ii个数小的,fi,j=fi,j+1+[ai>aj+1]f_{i,j}=f_{i,j+1}+[a_i>a_{j+1}],确定a,ca,c后,答案就是i=a+1c1fi,c\sum_{i=a+1}^{c-1}f_{i,c},维护下ff数组前缀和就可以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 en puts("")
#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 OP() {}
void op() {}
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 OP(T _, T2... oth)
{
	Out(_);
	putchar('\n');
	OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
	Out(_);
	putchar(' ');
	op(oth...);
}
/*#################################*/
const ll N=5005;
ll n;
ll arr[N];
int f[N][N],s[N][N];
void print()
{
	rep(i,1,n)
	{
		rep(j,i+1,n)
			op(f[i][j]);
		en;
	}
}
void solve()
{
	ll ans=0;
	read(n);
	rep(i,0,n+1)
		rep(j,0,n+1)
			f[i][j]=s[i][j]=0;
	rep(i,1,n)
		read(arr[i]);
	rep(i,1,n)
	{
		f[i][n]=0;
		for(int j=n-1;j>=i;--j)
			f[i][j]=f[i][j+1]+(arr[j+1]<arr[i]);
	}
	rep(i,1,n)
		rep(j,1,i-1)
			s[i][j]=s[i][j-1]+f[j][i];
	rep(a,1,n)
	{
		rep(c,a+2,n)
		{
			if(arr[c]<arr[a])
				continue;
			ans+=s[c][c-1]-s[c][a];
		}
			
	}
	OP(ans);
	
}
int main()
{
	int _;
	cin>>_;
	while(_--)
	{
		solve();
	}
}

D

思路

对行和列分开考虑。首先考虑列,发现对于imodmi\mod m相同的sis_i,每一轮覆盖的列是相同的,所以只需要存在一个iisi=1s_i=1,且ii%m还没有被覆盖过,就会贡献一次答案。

行的情况较复杂,设fi,jf_{i,j}s1s_1到达坐标(i,j)(i,j)时总共覆盖的行数,那么fi,j=fi1,j+f_{i,j}=f_{i-1,j}+新加入的一行是否存在11,用前缀和判断一下即可。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define per(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 en puts("")
#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 OP() {}
void op() {}
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 OP(T _, T2... oth)
{
	Out(_);
	putchar('\n');
	OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
	Out(_);
	putchar(' ');
	op(oth...);
}
/*#################################*/
const ll N=1e6+10;
ll n,m;
ll vis[N],ans[N],sum[N],f[N];
void solve()
{
	read(n,m);
	string s;
	cin>>s;
	s=' '+s;
	ll tot=n*m,cnt=0;
	rep(i,0,tot)
		vis[i]=ans[i]=sum[i]=f[i]=0;
	rep(i,1,tot)
	{
		if(!vis[i%m] && s[i]-'0')
		{
			vis[i%m]=1;
			++cnt;
		}
		ans[i]=cnt;
	}
	rep(i,1,tot)
		sum[i]=sum[i-1]+s[i]-'0';
	rep(j,1,m)
	{
		f[j]=!!sum[j];
		ans[j]+=f[j];
	}
	rep(i,2,n)
	{
		rep(j,1,m)
		{
			ll x=j+(i-2)*m;
			f[j]=f[j]+!!(sum[x+m]-sum[x]);
			ans[(i-1)*m+j]+=f[j];
		}
	}
	rep(i,1,tot)
		op(ans[i]);
	en;
}
int main()
{
	int _;
	cin>>_;
	while(_--)
	{
		solve();
	}	
}

E

思路

如果ai=bia_i=b_i不论怎么分配贡献都是00,只考虑不等的情况。发现上下对应的关系最终形成一个环(即aibiaj(aj=bi)bia_i\rightarrow b_i\rightarrow a_j(a_j=b_i)\rightarrow\cdots\rightarrow b_i)。对每一个环单独计算答案,一个环上的相邻节点肯定是一大一小贡献最大。

考虑一个特殊情况,就是环上最后染色的一个块,如果他前后一大一小,那么它取任意一个中间值得到的贡献总和都是一样的,所以就给他一个较靠近中间的值,防止他占用极大极小值影响其他位置贡献答案。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define per(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 en puts("")
#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 OP() {}
void op() {}
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 OP(T _, T2... oth)
{
	Out(_);
	putchar('\n');
	OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
	Out(_);
	putchar(' ');
	op(oth...);
}
/*#################################*/
const ll N=1e5+10;
ll L,R,n,flag;
ll a[N],b[N],c[N],pa[N],vis[N];
void print()
{
	rep(i,1,n)
		op(c[a[i]]);
	en;
	rep(i,1,n)
		op(c[b[i]]);
	en;
}
void dfs(ll u)
{
	vis[u]=1;
	ll nxt=pa[b[u]];
	if(c[b[nxt]])
	{
		vis[nxt]=1;
		if(!flag)
			c[b[u]]=--R;
		return;
	}
	if(!flag)
		c[b[u]]=--R;
	else
		c[b[u]]=++L;
	flag^=1;
	if(!vis[pa[b[u]]])
		dfs(pa[b[u]]);
}
void solve()
{
	read(n);
	L=0,R=n+1;
	rep(i,1,n)
		c[i]=vis[i]=0;
	rep(i,1,n)
	{
		read(a[i]);
		pa[a[i]]=i;
	}
	rep(i,1,n)
	{
		read(b[i]);
	}
	rep(i,1,n)
		if(!vis[i] && a[i]!=b[i])
		{
			flag=0;
			c[a[i]]=++L;
			dfs(i);
		}
	rep(i,1,n)
		if(!c[i])
		{
			c[i]=++L;
		}
	ll ans=0;
	rep(i,1,n)
		ans+=abs(c[a[i]]-c[b[i]]);
	OP(ans);
}
int main()
{
	int _;
	cin>>_;
	while(_--)
	{
		solve();
	}
}