atcoder beginner contest 416
A
void solve(){
int n;cin>>n;
int l,r;cin>>l>>r;
string s;cin>>s;
s=" "+s;
for(int i=l;i<=r;i++){
if(s[i]=='x'){
cout<<"No"<<endl;
return;
}
}
cout<<"Yes"<<endl;
}
B
题意:给定一个由#,.,o组成的字符串,修改字符串的.,使得o尽量多,且满足每个o之间隔着一个#
void solve(){
string s;cin>>s;
int n=s.size();
s=" "+s;
vector<char>t(n+1);
vector<int>vis(n+1);
rep(i,1,n){
if(s[i]=='#'){
t[i]='#';
vis[i]=1;
}
}
//1 0
//2 3
int last=0;
rep(i,1,n){
if(s[i]=='#'){
int ok=0;
for(int j=last+1;j<=i-1;j++){
if(s[j]=='o')ok=1;
}
if(ok)break;
else{
for(int j=last+1;j<=i-1;j++){
if(s[j]=='.'){
s[j]='o';break;
}
}
}
last=i;
}
}
int ok=0;
for(int j=last+1;j<=n;j++){
if(s[j]=='o')ok=1;
}
if(!ok){
for(int j=last+1;j<=n;j++){
if(s[j]=='.'){
s[j]='o';
break;
}
}
}
rep(i,1,n){
cout<<s[i];
}
}
C
题意:给定n个字符串,把其中的k个拼接在一起,求字典序第x小的字符串
思路:
n^k<1e5,dfs+排序即可
int n,k,x;
vector<string>v;
void dfs(string s,vector<string>&a,int cal){
if(cal==k){
v.pb(s);return;
}
for(int i=1;i<=n;i++){
dfs(s+a[i],a,cal+1);
}
}
void solve(){
cin>>n>>k>>x;
vector<string>a(n+1);
rep(i,1,n)cin>>a[i];
dfs("",a,0);
sort(v.begin(),v.end());
x--;
cout<<v[x]<<endl;
}
D
题意:给定两个数组a和b和数字m,可以重排a,使得 sigma(1<=i<=n)(a_i+b_i)%m 最小
思路:
贪心
发现ai和bi的范围都是小于m的
因此我们有 0<ai+bi<2m
所以 ai+bi = c 或 ai+bi = m + c (c<m)
我们的目标是减小c之和
枚举b,发现要么取a中最小的,要么取 ai= m+c -bi ,即ai中大于等于m-bi的
两者比较取min
a的元素考虑使用multiset维护
显然,这样局部贪心能获得最优解
void solve(){
int n,m;cin>>n>>m;
vector<int>a(n+1);rep(i,1,n)cin>>a[i];
vector<int>b(n+1);rep(i,1,n)cin>>b[i];
vector<int>vis(n+1);
multiset<int>at;
rep(i,1,n)at.insert(a[i]);
sort(a.begin()+1,a.end());
int ans=0;
rep(i,1,n){
int res=(b[i]+*(at.begin()))%m;
auto it=at.lower_bound(m-b[i]);
if(it!=at.end()){
int res2=(b[i]+*(it))%m;
if(res2<res){
at.erase(it);
ans+=res2;
}else{
at.erase(at.begin());
ans+=res;
}
}else{
at.erase(at.begin());
ans+=res;
}
}
cout<<ans<<endl;
}
E
题意:给定n个点的图(n<=500),m条边长度为C_i,其中有k个点有机场可以相互以T的时间到达
3种查询
- 1.x,y之间建一条长度为c的边
- 2.在x点上建一个机场
- 3.输出 sigma(1<=i<j<=n)f(i,j)(其中f(i,j)表示i->j的最短路,当然图是无向的)
查询次数q<=1000
思路:
n=500,显然floyd
只有1,3查询的话,十分容易维护,只需要在加边的时候n^2判断一下i->j的最短路是否变为i->x->y->j或i->y->x->j即可
对于查询2,我们直接建边发现不好维护
不妨设一个sky点(第n+1个点),其中有机场的点到sky耗费T,sky到有机场的点耗费0
这样和上述一样维护就可以,floyd此时跑n+1
int d[505][505];
int air[505];
void solve(){
int n,m;cin>>n>>m;
int sky=n+1;
rep(i,1,n+1)rep(j,1,n+1){
if(i==j)continue;
d[i][j]=1e18;
}
//第n+1点为sky点
//有机场的点可以以T的代价到达sky点
//sky点可以以0的代价到达任意有机场的点
rep(i,1,m){
int u,v,c;cin>>u>>v>>c;
d[u][v]=min(d[u][v],c);
d[v][u]=min(d[v][u],c);
}
int k,T;cin>>k>>T;
rep(i,1,k){
int x;cin>>x;
air[x]=1;
d[x][sky]=T;
d[sky][x]=0;
}
{//floyd
rep(k,1,n+1){
rep(i,1,n+1){
rep(j,1,n+1){
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
}
int q;cin>>q;
while(q--){
int opt;cin>>opt;
if(opt==1){
int x,y,c;cin>>x>>y>>c;
int tmp=d[x][y];
d[x][y]=min(d[x][y],c);
d[y][x]=min(d[y][x],c);
if(tmp>c){
rep(i,1,n+1){
rep(j,1,n+1){
d[i][j]=min({d[i][j],d[i][x]+c+d[y][j],d[i][y]+c+d[x][j]});
}
}
}
}else if(opt==2){
int x;cin>>x;
if(air[x])continue;
air[x]=1;
d[x][sky]=T;
d[sky][x]=0;
rep(i,1,n+1){
rep(j,1,n+1){
d[i][j]=min({d[i][j],d[i][x]+T+d[sky][j],d[i][sky]+0+d[x][j]});
}
}
}else{
int ans=0;
rep(i,1,n){
rep(j,i+1,n){
ans+=(d[i][j]>=1e18?0:d[i][j]);
}
}
cout<<ans*2<<endl;
}
}
}

浙公网安备 33010602011771号