ABC288 解题报告【A~D+F】
Atcoder Beginner Contest 288
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\) 为所组成的数值。)
显然 TLE。考虑优化,可以发现 \(\operatorname{int}(l,r)=10\cdot\operatorname{int}(i,r-1)+x_r(l<r)\)。
于是:
其中,加号右边的求和可以用变量 \(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];
}