Atcoder Beginner Contest 315 D~G
D
题意:给定一个
- 对于每一行,若有且仅有一种字符存在,且个数大于1,将这些字符标记
- 对于每一列,若有且仅有一种字符存在,且个数大于1,将这些字符标记
- 删除所有标记的字符
求最后还能剩下多少字符。
注意到每一行每一列最多被删一次,我们可以用队列模拟这个操作,每次更新时间复杂度是
时间复杂度
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 505050
char a[5050][5050];
int h[5050][300],r[5050][300],vis[5050][5050],s[N][2],n,m,sur[N][2];
struct node{
int id,opt;
};
queue<node>q;
signed main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
h[i][a[i][j]-'a']++,r[j][a[i][j]-'a']++;
s[i][0]++,s[j][1]++;
}
}
for(int i=1;i<=n;i++)for(int j=0;j<26;j++)sur[i][0]+=(h[i][j]>0);
for(int i=1;i<=m;i++)for(int j=0;j<26;j++)sur[i][1]+=(r[i][j]>0);
for(int i=1;i<=n;i++)if(sur[i][0]==1&&s[i][0]!=1){
q.push((node){i,0});
}
for(int i=1;i<=m;i++)if(sur[i][1]==1&&s[i][1]!=1){
q.push((node){i,1});
}
while(!q.empty()){
node u=q.front();q.pop();
if(u.opt==0){
for(int i=1;i<=m;i++){
if(vis[u.id][i]==0){
vis[u.id][i]=1;r[i][a[u.id][i]-'a']--;s[i][1]--;
if(r[i][a[u.id][i]-'a']==0){
sur[i][1]--;if(sur[i][1]==1&&s[i][1]!=1)q.push((node){i,1});
}
}
}
}
else {
for(int i=1;i<=n;i++){
if(!vis[i][u.id]){
vis[i][u.id]=1;h[i][a[i][u.id]-'a']--;s[i][0]--;
if(h[i][a[i][u.id]-'a']==0){
sur[i][0]--;
if(sur[i][0]==1&&s[i][0]!=1)q.push((node){i,0});
}
}
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
ans+=(vis[i][j]==0);
}
}
cout<<ans<<"\n";
}
E
题意:给定若干本书,在读第
求一个读书顺序,使得读的书最少且满足读了这些书之后就可以读第一本书。数据保证有解。
首先,我们建立两张有向图,第一张图的边形如
然后我们在第一张图从点1开始跑,标记到达的所有点,这些书是必读书,其他书没有任何关系。
接下来这个顺序,便可以在第二张图里只对被标记的点进行Topsort即可。
F
赛上一直以为是优先队列模拟,最后3min意识到是DP,却是没了时间。
题意:给定
现在你可以选择跳过其中一部分点,不可以跳过点1和点
求你最终需要付出的代价最小值。你的答案不可以和标准答案误差超过
范围:
首先估计答案上界,不跳过点,其代价最多为
所以说,
怎么算?最优化问题,可以选择跳过,问题可划分可拼凑,明显的动态规划。
设
显然有
然后枚举答案,
当附加代价单一可以通过某参数单独计算时,可先不考虑附加代价,最后处理即可。
signed main(){
cin>>n;
db ans=1e18;
for(int i=1;i<=n;i++)cin>>x[i]>>y[i];
f[1][0]=0;
for(int j=0;j<=30ll;j++){
for(int i=2;i<=n;i++){
f[i][j]=1e18;
for(int k=1;k<i;++k)if(i-k-1<=j)f[i][j]=min(f[i][j],f[k][j-(i-k-1)]+dis(i,k));
}
}
for(int c=0;c<=30;++c){
db res;
if(c==0)res=0;
else res=(1<<(c-1));db mn=1e18;
for(int i=0;i<=min(n,c);i++)mn=min(mn,f[n][i]);
res+=mn;
ans=min(ans,res);
}
printf("%.15f",ans);
}
G
题意:给定
在这个问题中,注意到下界是1,不方便处理,可令
首先,注意到
设 continue
。
我们设
然后,我们对于
此时注意到合法的系数必定是在一段区间之内,设端点为
注意以下简称系数是指周期数,也即解的个数。
此时必定有
这是要找出令
综上,
然后考虑求最大解。有两种情况:
- 一是由
来决定,它取最小值时, 取得最大系数,是 (之所以下取整是要留一个最小非负解)。 - 二是由
来决定,它最大可以取到 。
所以
当然,若
#include<bits/stdc++.h>
using namespace std;
#define int long long
int get(int a,int b,int c,int &x,int &y){//ax+by=c
int d=exgcd(a,b,x,y);x*=c/d,y*=c/d;
return d;
}
int N,A,B,C,X;
signed main(){
ios::sync_with_stdio(false);
cin>>N>>A>>B>>C>>X;
N--,X-=A+B+C;
if(X<0){
puts("0");return 0;
}
int x0,y0;
int d=exgcd(B,C,x0,y0),b=B/d,c=C/d,ans=0;//k0=b,k1=c
x0%=c;y0=(d-B*x0)/C;
for(int i=0;i<=N;i++){
int x=X-i*A;
if(x%d!=0)continue;
if(x<0)break;
int l,r,x1=x/d%c*x0,y1;x1=(x1%c+c)%c,y1=(x-x1*B)/C;
l=max(0ll,(y1-N+b-1ll)/b);
if(x1>N||y1<0)r=-1ll;
else r=min((N-x1)/c,y1/b);
if(l<=r)ans+=r-l+1;
}
cout<<ans;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!