A. Shortest Path with Obstacle
当两个点的x坐标或者y坐标相同的时候,需要多花2费绕开
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
void solve()
{
int x1,y1,x2,y2,x3,y3;
cin>>x1>>y1>>x2>>y2>>x3>>y3;
int ans;
if(x1==x2&&x2==x3&&y3<=max(y1,y2)&&y3>=min(y1,y2))ans=abs(y2-y1)+2;
else if(y1==y2&&y2==y3&&x3<=max(x1,x2)&&x3>=min(x1,x2))ans=abs(x2-x1)+2;
else ans=abs(x1-x2)+abs(y1-y2);
cout<<ans<<endl;
}
int main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
B. Alphabetical Strings
某个字符数量大于1则无解,记录a的位置。若没有a的位置则无解。然后从a的位置用双指针l r
,看看l-1或者r+1
位置的字符是不是我们要的,是的话移动指针,依次判断每个字符,最后判断r-l+1是否是(最大字符-最小字符+1)
即可。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
char s[N];
void solve()
{
map<char,int>cnt;
cin>>s+1;
int n=strlen(s+1),l=0,r=0;
char ma='a';
for(int i=1;i<=n;i++)
{
cnt[s[i]]++;
if(s[i]=='a')l=r=i;
ma=max(ma,s[i]);
}
for(auto i:cnt)
{
if(i.second>1||!l)
{
puts("no");
return ;
}
}
char now='b';
while(now<=ma)
{
if(s[l-1]==now)l--;
else if(s[r+1]==now)r++;
now++;
}
if(r-l+1==ma-'a'+1)puts("yes");
else puts("no");
}
int main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
C. Pair Programming
每次取出a,b数组中较小的数字即可。如果较小的取出来也不合法,那就无解。最后如果某个数组有剩余元素也记得取出来。用两个队列或者两个指针模拟即可。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],b[N];
void solve()
{
int k,n,m;
cin>>k>>n>>m;
for(int i=1; i<=n; i++)cin>>a[i];
for(int i=1; i<=m; i++)cin>>b[i];
int i=1,j=1;
vector<int>ans;
bool f=1;
while(i<=n&&j<=m)
{
if(k<min(a[i],b[j]))
{
f=0;
break;
}
if(a[i]<b[j])
{
if(a[i]==0)k++;
ans.push_back(a[i]);
i++;
}
else
{
if(b[j]==0)k++;
ans.push_back(b[j]);
j++;
}
}
while(i<=n)
{
if(k<a[i])
{
f=0;
break;
}
if(a[i]==0)k++;
ans.push_back(a[i]);
i++;
}
while(j<=m)
{
if(k<b[j])
{
f=0;
break;
}
if(b[j]==0)k++;
ans.push_back(b[j]);
j++;
}
if(f)
{
for(auto i:ans)printf("%d ",i);
puts("");
}
else puts("-1");
}
int main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
D. Co-growing Sequence
首先确定b数组可以用递推的方式,先看第一个和第二个数,我肯定是对第二个数操作更好,因为这样字典序更小。所以b[1]=0
。若要满足a[i-1]&a[i]=a[i-1]
,即让a[i]=a[i-1]|a[i]
,记录一下上一个a[i-1]^b[i-1]
的值记做x
。那么(x|a[i])^a[i]
就是b[i]
的值。^b[i]
相当于补一些值给他。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N];
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
printf("0");
int now;
for(int i=2;i<=n;i++)
{
now=(a[i-1]|a[i])^a[i];
printf(" %d",now);
a[i]|=a[i-1];
}
puts("");
}
int main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
E. Air Conditioners(dp)
记l[i]
为只考虑i左侧所有空调对i的温度最小值。那么l[i]=min(l[i-1]+1,c)
c为i这个点的空调温度,如果这个点没有空调c取无穷大即可,或者写个if判断一下。同理记录一个r[i]
最后对每个点取min(l[i],r[i])
就是答案
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10,inf=0x3f3f3f3f;
int l[N],r[N],a[N],b[N];
void solve()
{
int n,k;
cin>>n>>k;
for(int i=1;i<=k;i++)cin>>a[i];
for(int i=1;i<=k;i++)cin>>b[i];
map<int,int>m;
for(int i=1;i<=k;i++)m[a[i]]=b[i];
l[0]=inf,r[n+1]=inf;
for(int i=1;i<=n;i++)
{
l[i]=l[i-1]+1;
if(m[i])l[i]=min(l[i],m[i]);
}
for(int i=n;i>=1;i--)
{
r[i]=r[i+1]+1;
if(m[i])r[i]=min(r[i],m[i]);
}
for(int i=1;i<=n;i++)printf("%d ",min(l[i],r[i]));
puts("");
}
int main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
F. Array Stabilization (GCD version)(二分,线段树)
建立一颗线段树,维护l-r
的gcd
将原来的数组复制一份到数组的尾巴。
二分操作次数k
。然后检查是不是所有的i~i+k+1-1
gcd都一样即可。
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10,inf=0x3f3f3f3f;
int w[N],n,q,k;
struct node
{
int l,r;
int v;
} tr[4*N];
inline void pushup(int u)
{
tr[u].v=__gcd(tr[u<<1].v,tr[u<<1|1].v);
}
void build(int u,int l,int r)
{
if(l==r)
{
tr[u]= {l,l,w[l]};
return ;
}
tr[u]= {l,r};
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
int query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r)return tr[u].v;
int mid=tr[u].l+tr[u].r>>1;
int v=0;
if(l<=mid)v=query(u<<1,l,r);
if(r>mid)v=__gcd(query(u<<1|1,l,r),v);
return v;
}
bool check(int mid)
{
mid++;
int now=query(1,1,mid);
for(int i=2;i+mid-1<=n;i++)
{
if(query(1,i,i+mid-1)!=now)return 0;
}
return 1;
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)scanf("%d",&w[i]),w[i+n]=w[i];
n*=2;
build(1,1,n);
int l=0,r=1e6;
while(l<r)
{
int mid=l+r>>1;
if(check(mid))r=mid;
else l=mid+1;
}
printf("%d\n",r);
}
int main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
G. How Many Paths? (tarjan缩点,拓扑排序,dp)
首先缩点,然后对强连通分量建图,在强连通分量上跑拓扑排序dp即可。
有几个坑点
1.注意自环要特判
2.假如某个点x存在自环。若1号点到不了x,那么x点的答案应该是0,而不是-1
3.强连通分量大小>1则这个分量里所有点距离设成无穷大
具体看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e5+10,inf=0x3f3f3f3f;
int dfn[N],low[N],scc_cnt,id[N],Size[N],times,stk[N],top;
ll ans[N],res[N];
bool in[N],vis[N];
vector<int>g[N];
vector<int>G[N];
void tarjan(int u)
{
dfn[u]=low[u]=++times;
stk[++top]=u,in[u]=1;
for(auto j:g[u])
{
if(!dfn[j])
{
tarjan(j);
low[u]=min(low[u],low[j]);
}
else if(in[j])
low[u]=min(low[u],dfn[j]);
}
if(dfn[u]==low[u])
{
int y;
scc_cnt++;
do
{
y=stk[top--];
in[y]=0;
id[y]=scc_cnt;
Size[scc_cnt]++;
}while(y!=u);
}
}
void solve()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
res[i]=ans[i]=vis[i]=0;
g[i].clear();
G[i].clear();
times=scc_cnt=in[i]=dfn[i]=low[i]=Size[i]=stk[i]=id[i]=top=0;
}
unordered_map<int,int>ban;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
if(u!=v)g[u].push_back(v);
else ban[u]=1;
}
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
for(int i=1;i<=n;i++)
for(auto j:g[i])
{
int a=id[i],b=id[j];
if(a!=b)G[a].push_back(b);
}
ans[id[1]]=1;
vis[id[1]]=1;
for(auto i:ban)ans[id[i.first]]=-inf;
for(int i=1;i<=n;i++)if(Size[id[i]]>1)ans[id[i]]=-inf;
for(int i=id[1];i;i--)
for(auto j:G[i])
{
ans[j]+=ans[i];
if(vis[i])vis[j]=1;
ans[j]=min(ans[j],2ll);
}
for(int i=1;i<=n;i++)
{
if(!vis[id[i]])res[i]=0;
else if(ans[id[i]]<0)res[i]=-1;
else res[i]=ans[id[i]];
printf("%lld ",res[i]);
}
puts("");
}
int main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
/*
1
3 3
1 1
2 2
3 3
*/