abc377
A. Rearranging ABC
-
题意:求给定的字符串是不是
ABC。 -
思路:直接判断。
void solve(){
cin>>s;
for(auto x:s){
S[x]++;
}
if(S['A']==1&&S['B']==1&&S['C']==1){
cout<<"Yes"<<endl;
}else{
cout<<"No"<<endl;
}
}
B. Avoid Rook Attack
- 题意:一个棋子在图中记为
*,跟它同一行或同一列不能放*,问还有几个方格能放棋子。 - 思路:因为 $n$ 很小,直接暴力枚举整张图,把能被覆盖到的标记,此时剩下的就是答案。
char s[10][10];
int n=8;
bool vis[10][10];
void solve(){
vector<PII>t;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>s[i][j];
if(s[i][j]=='#'){
t.push_back({i,j});
}
}
}
for(auto [x,y]:t){
for(int i=1;i<=n;i++){
vis[x][i]=1;
vis[i][y]=1;
}
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
ans+=(vis[i][j]==0);
}
}
cout<<ans<<endl;
}
C. Avoid Knight Attack
-
题意:一个棋子可以像中国象棋的 “马” 那样走 “日” 覆盖,问图中没有被棋子覆盖的地方的方格数。
-
思路:直接用
set去维护每个棋子能覆盖到的点,因为set自带去重功能,最后直接把棋盘大小减去set的元素的个数就是答案。
int n,m;
int dx[]={1,2,2,1,-1,-2,-2,-1};
int dy[]={2,1,-1,-2,-2,-1,1,2};
void solve(){
cin>>n>>m;
set<PII>S;
for(int i=1;i<=m;i++){
int a,b;
cin>>a>>b;
for(int j=0;j<8;j++){
int x=a+dx[j],y=b+dy[j];
if(x<1||y<1||x>n||y>n)continue;
S.insert({x,y});
}
S.insert({a,b});
}
cout<<((long long)n*n-(long long)S.size())<<endl;
}
D. Many Segments 2
-
题意:给定 $n$ 个区间,求出区间 $[l,r]$ 不完全包含区间 $[L_i,R_i]$ 的区间个数。
-
思路:因为数据规模比较大,对于这种求个数的问题可以考虑贡献法。然后我们又发现了:如果固定 $l$ 的话,它的答案是取决于所有 $L_i>=l$ 的区间中 $R_i$ 最小的。此时我们用双指针来做,此时从大到小枚举 $l$ 的时候(为什么从大到小,因为你更新最小值的时候肯定是从大到小来维护的),$L_i>=l$ 的区间会逐渐变多,此时统计右端点即可,然后每次更新一下最小值即可。
void solve() {
cin>>n>>m;
FOR(i,1,n){
int x,y;
cin>>x>>y;
w[i]={x,y};
}
sort(w+1,w+1+n);
int lst=m+1;
int ans=0;
int j=n;
FORD(i,1,m){
while(j>=1&&w[j].fi>=i){
lst=min(lst,w[j].se);
j--;
}
ans+=(lst-i);
}
cout<<ans<<endl;
}
E. Permute K times 2
-
题意:给定排列,然后每次操作将 $P_i$ 更新为 $P_{P_i}$,问第 $k$ 次操作 $P$ 的结果。
-
思路:对于这种题,可以考虑结合图来做,也就是画图。通过画图,可以很容易知道最后肯定会形成一个环,具体字怎么画呢?就是将 $P_i$ 与 $P_{P_i}$ 连边。

-
通过手算可以知道:它的第一个数在 $5$ 次操作的值是 $5,2,4,6,5$,解释一下就是:操作一次从 $5\rightarrow 2$,也就是走一步;然后第二次操作从 $2\rightarrow 4$,在图上走两步。以此类推,若要一个数按题目要求变换 $k$ 次,那么它的值将变为它向箭头方向走 $k-1$ 步的值。
void dfs(int u){
vis[u]=1;
a[cnt].push_back(u);
for(auto j:g[u]){
if(vis[j])continue;
dfs(j);
}
}
int qmi(int a,int b,int p){
int res=1;
while(b){
if(b&1)res=res*a%p;
a=a*a%p;
b/=2;
}
return res;
}
void solve(){
cin>>n>>k;
for(int i=1;i<=n;i++){
int x;
cin>>x;
g[i].emplace_back(x);
}
for(int i=1;i<=n;i++){
if(!vis[i])cnt++,dfs(i);
}
for(int i=1;i<=cnt;i++){
int s=qmi(2,k,(int)a[i].size());
for(int j=0;j<a[i].size();j++){
w[a[i][j]]=a[i][(j+s)%(int)a[i].size()];
}
}
for(int i=1;i<=n;i++)cout<<w[i]<<' ';
}
F. Avoid Queen Attack
-
题意:对于一个棋子,它可以覆盖的范围类似 “米” 字形。给定一张图,问最后可以放棋子的格子数。
-
思路:如果是十字的话还好做,但这道题有对角线,因此对于对角线,我们可以取个巧,就是让 $x+y$ 作为
/形对角线,让 $x-y$ 最为\形对角线,那么对于/对角线的取值范围就是 $[n+1,2n]$,对于\对角线的取值范围就是 $[0,n-1]$ 。此时我们可以先去让\形对角线满足条件,因为/\会有交点。这样的话我们可以先把十字形的先去掉,也就是先把十字形覆盖的格数算出来,从剩下的个数进行对角线的选择。然后根据*的横坐标、纵坐标和\形对角线,此时要看\形对角线能覆盖到哪里,可以算:(比如现在是已知横坐标和对角线去求 $y$ 就是 $d=x-y$ => $y=x-d$,然后最后的答案假如对于某个\对角线,是把对角线长度 $n-d$ 减去被对角线覆盖到的格子数(已经被覆盖到的格子数))。当开始枚举另一边的时候得注意:中间重复部分,此时可以列出方程 $a=x-y,b=x+y$ 解得:$x=(a+b)/2,y=(b-a)/2$,注意 $x,y$ 均为整数,如果能整除的话说明有交点,反之没有。
void solve(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int a,b;
cin>>a>>b;
ht.insert(a);
vt.insert(b);
zhu.insert(a-b);
fu.insert(a+b);
}
int ans=(n-ht.size())*(n-vt.size());
for(auto d:zhu){
set<int>cs;
for(auto x:ht){
int y=x-d;
if(y>=1&&y<=n){
cs.insert(x);
}
}
for(auto y:vt){
int x=d+y;
if(x>=1&&x<=n){
cs.insert(x);
}
}
int num=cs.size();
int len_d=n-abs(d);
ans-=(len_d-num);
}
for(auto e:fu){
set<int>cs;
for(auto x:ht){
int y=e-x;
if(y>=1&&y<=n){
cs.insert(x);
}
}
for(auto y:vt){
int x=e-y;
if(x>=1&&x<=n){
cs.insert(x);
}
}
for(auto d:zhu){
int x=(d+e)/2;
int y=(e-d)/2;
if((e+d)%2==0&&x>=1&&x<=n&&y>=1&&y<=n){
cs.insert(x);
}
}
int num=cs.size();
int len_d=n-abs(e-(n+1));
ans-=(len_d-num);
}
cout<<ans<<endl;
}
G. Edit to Match
-
题意:给你 $n$ 个字符串,记 $s_0$ 为空,对于每个字符串 $i\in[1,n]$,求通过删除/添加后缀字母的操作,最少需要操作多少次使得 $s_i=s_k,k\in[0,i-1]$。
-
思路:这就是很典型的字符串匹配,对于字符串的前缀匹配,可以考虑字典树。将每个数插入到类似于
trie树的东西上,再用 $en_i$ 数组记录离这个节点最近的结尾字符,代价即为:$en_p+n-i+1$,取最小值即可。其中 $en_i$ 就是cnt数组。
void insert(){
int p=0,n=s.size();
ans=n;
for(int i=0;i<n;i++){
int u=s[i]-'a';
if(tr[p][u]==0)tr[p][u]=++idx;
p=tr[p][u];
ans=min(ans,cnt[p]+n-i-1);
cnt[p]=min(cnt[p],n-i-1);
}
cout<<ans<<endl;
}
void solve(){
cin>>n;
memset(cnt,0x3f,sizeof cnt);
cnt[0]=0;
for(int i=1;i<=n;i++){
cin>>s;
insert();
}
}

浙公网安备 33010602011771号