ABC288 解题报告【A~D+F】

Atcoder Beginner Contest 288

Contest link

My result

A - Many A+B Problems

多测板题?

int a,b;
void Solve()
{
	int T;
	cin>>T;
	while(T--)
	{
		cin>>a>>b;
		cout<<a+b<<endl;
	}
}

B - Qualification Contest

给前 \(k\) 个字符串排序即可。

int n,k;
string s[105];
void Solve()
{
	cin>>n>>k;
	for(int i=1;i<=k;i++)cin>>s[i];
	sort(s+1,s+k+1);
	for(int i=1;i<=k;i++)cout<<s[i]<<endl;
}

C - Don't be cycle

对于一个 \(v\) 个点 \(e\) 条边的连通块,需要删除 \(e-v+1\) 条边。直接把图 dfs 一遍就行了。

const int N=200005;
int n,m,u,v,V,E,ans;
int head[N],nxt[N<<1],to[N<<1],tot;
void Add(int u,int v){to[++tot]=v,nxt[tot]=head[u],head[u]=tot;}
bool vis[N],Vis[N];
void dfs(int x)
{
	if(Vis[x])return;
	vis[x]=1,Vis[x]=1;V++;
	for(int i=head[x];i;i=nxt[i])
		if(!vis[to[i]])
		{
			E++;
			dfs(to[i]);
		}
	vis[x]=0;
}
void Solve()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>u>>v;
		Add(u,v);Add(v,u);
	}
	for(int i=1;i<=n;i++)
		if(!Vis[i])
		{
			V=E=0;
			dfs(i);
			ans+=E-V+1;
		}
	cout<<ans;
}

D - Range Add Query

结论:一个子段是好的当且仅当对于所有 \(0\le i<k\),子段中所有满足 \(j\bmod k=i\)\(a_j\) 的和(记为 \(S_k\))相等。

证明:
对于一个序列,操作显然是从左到右操作的。对于一次操作,每个 \(S_k\) 一定增加 \(c\)。如果 \(S_k\) 有不相等的,不可能让 \(S_k\) 全部变为 \(0\),进而不能将 \(a_i\) 全部归零。必要性证毕。
如果所有 \(S_k\) 相等,则依次对每个 \(l\le i\le r-k+1\),将 \(a_i\sim a_{i+k-1}\) 减去 \(a_i\)。操作完毕后,显然 \(a_{r-k+1}\) 之前的数全部归零,所以 \(S_{(r-k+1)\bmod k}=0\),进而所有 \(S_i\)\(0\),即所有 \(a_i\) 归零。充分性证毕。

综上,维护模前缀和 \(sum_{i,j}=\sum\limits_{p=1}^i[p\bmod k=j]\cdot a_p\ (0\le i\le n,0\le j<k)\),查询时检查所有的 \(sum_{r,i}-sum_{l-1,i}\) 是否相等就行了。

const int N=200005;
int n,k,q,l,r;
ll a[N],sum[N][15],s;
bool ok;
void Solve()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<k;j++)sum[i][j]=sum[i-1][j];
		sum[i][i%k]+=a[i];
	}
	cin>>q;
	while(q--)
	{
		cin>>l>>r;
		s=sum[r][0]-sum[l-1][0];ok=1;
		for(int i=1;i<k;i++)
			if(sum[r][i]-sum[l-1][i]!=s){ok=0;break;}
		cout<<(ok?"Yes":"No")<<endl;
	}
}

E - Wish List

F - Integer Division

显然无法暴力计算,考虑 dp:(以下定义 \(\operatorname{int}(l,r)\)\(x\)\(l\)\(r\) 为所组成的数值。)

\[dp_i=\sum\limits_{j=0}^{i-1}dp_j\cdot\operatorname{int}(j+1,i) \]

显然 TLE。考虑优化,可以发现 \(\operatorname{int}(l,r)=10\cdot\operatorname{int}(i,r-1)+x_r(l<r)\)

于是:

\[\begin{aligned}&dp_i\\=&\sum\limits_{j=0}^{i-1}dp_j\cdot\operatorname{int}(j+1,i)\\=&\sum\limits_{j=0}^{i-2}\left(dp_j\cdot\left(\operatorname{int}(j+1,i-1)\cdot10+x_i\right)\right)+dp_{i-1}\cdot x_i\\=&\sum\limits_{j=0}^{i-2}dp_j\cdot\operatorname{int}(j+1,i-1)\cdot10+\sum\limits_{j=0}^{i-2}dp_j\cdot x_i+dp_{i-1}\cdot x_i\\=&10\cdot\sum\limits_{j=0}^{i-2}dp_j\cdot\operatorname{int}(j+1,i-1)+\sum\limits_{j=0}^{i-1}dp_j\cdot x_i\\=&10\cdot dp_{i-1}+x_i\cdot\sum\limits_{j=0}^{i-1}dp_j\end{aligned} \]

其中,加号右边的求和可以用变量 \(sum\) 记录。于是总复杂度降为 \(O(n)\)

const int MOD=998244353;
struct ModInt
{
	ll val;
	ModInt(ll v=0){val=v%MOD;}
	operator ll(){return val;}
	ModInt operator=(const ll v){return (*this)=ModInt(v);}
	ModInt operator+(const ModInt B)const{return (val+B.val)%MOD;}
	ModInt operator+=(const ModInt B){return (*this)=(*this)+B;}
	ModInt operator-(const ModInt B)const{return (val-B.val+MOD)%MOD;}
	ModInt operator-=(const ModInt B){return (*this)=(*this)-B;}
	ModInt operator*(const ModInt B)const{return val*B.val%MOD;}
	ModInt operator*=(const ModInt B){return (*this)=(*this)*B;}
};
istream& operator>>(istream &in,ModInt &A)
{
	in>>A.val;A.val%=MOD;
	return in;
}
ostream& operator<<(ostream &out,const ModInt A)
{
	out<<A.val;
	return out;
}
const int N=200005;
int n;
string x;
ModInt dp[N],sum;
void Solve()
{
	cin>>n>>x;x=' '+x;
	dp[1]=x[1]-'0';sum=dp[1]+ModInt(1);
	for(int i=2;i<=n;i++)
		dp[i]=dp[i-1]*ModInt(10)+sum*ModInt(x[i]-'0'),\
		sum+=dp[i];
	cout<<dp[n];
}
posted @ 2023-02-07 13:51  No_Play_Yes_Splay  阅读(82)  评论(0编辑  收藏  举报