【M Contect-Div.3】#4 题解
本帖由 mengnn 编写,若有疏漏感谢指出。
本帖 2125.13.31 完工。
A. Rock-Strings-Decipher 题解
题面及思路
简单的模拟和判断,从头到尾把字符串看一遍就好,就不过多赘述,直接粘的 #2 T1 的解释。
注意:str=s[i]+str 等代码复杂度是 reverse() 函数。
时间复杂度
简单的线形级复杂度,若设输入总字符数为
AC Code:
#include<bits/stdc++.h>
using namespace std;
const int N=105;
int n,a[N];
string s[N];
int main(){
cin>>n;
for (int i=1;i<=n;i++) cin>>s[i];
for (int i=1,x;i<=n;i++) cin>>x,a[abs(x)]=i*(abs(x)/x);
for (int i=1;i<=n;i++){
if (a[i]<0) reverse(s[-a[i]].begin(),s[-a[i]].end());
cout<<s[abs(a[i])]<<' ';
}
return 0;
}
代码来自 @mengnn。
B. Rock-Strings-Real 题解
题面及思路
这个题代码很简单,虽然
因为要维护定位删点增点序列,所以我们可以考虑简单数据结构——链表。它可以把
对于
if (op==1){
nxt[++sz]=nxt[mp[x]];
vtx[sz]=y;
nxt[mp[x]]=sz;
mp[y]=sz;
}
观察到有一个 mp 数组,其意为某字符串的链表内编号。
对于
string ans1="",ans2="";
for (int i=mp[x],j=mp[y];i||j;ans1+=(vtx[i]!=y?vtx[i]:""),ans2+=(vtx[j]!=x?vtx[j]:"")){
if (vtx[i]==y){
ans^=f(ans1);
nxt[mp[x]]=mp[y];
break;
}
if (vtx[j]==x){
ans^=f(ans2);
nxt[mp[y]]=mp[x];
break;
}
if (i) i=nxt[i];
if (j) j=nxt[j];
}
最后我们只需完成最终“进制转换”的 f() 函数,这里非常简单,就不过多赘述:
inline int f(string &s){
long long cnt=0;
for (char c:s) cnt=(cnt*26+c-'a')%P;
return (int)(cnt%P);
}
全部完成后你就会发现,你这样“
注意:如果你链表模拟的 map 定义为 map<string,string>,那就会莫名奇妙出很多错,时间复杂度甚至不如暴力,建议写为 map<string,int>。
时间复杂度
简单观察容易发现,事实上,你链表的每个点只会被插入和删除最多一次,于是总共的次数便是
于是,本“暴力”代码的真实时间复杂度是 map<string,int> 存储会带一个
AC Code:
#include <bits/stdc++.h>
using namespace std;
const int N=5e5+5;
const int P=1e9+7;
int q,nxt[N],sz=1;
map<string,int> mp;
string s,vtx[N];
inline int f(string &s){
long long cnt=0;
for (char c:s) cnt=(cnt*26+c-'a')%P;
return (int)(cnt%P);
}
int main(){
cin>>q>>s;
mp[s]=1;vtx[1]=s;
int ans=0;
while (q--){
int op;
string x,y;
cin>>op>>x>>y;
if (op==1){
nxt[++sz]=nxt[mp[x]];
vtx[sz]=y;
nxt[mp[x]]=sz;
mp[y]=sz;
}else{
string ans1="",ans2="";
for (int i=mp[x],j=mp[y];i||j;ans1+=(vtx[i]!=y?vtx[i]:""),ans2+=(vtx[j]!=x?vtx[j]:"")){
if (vtx[i]==y){
ans^=f(ans1);
nxt[mp[x]]=mp[y];
break;
}
if (vtx[j]==x){
ans^=f(ans2);
nxt[mp[y]]=mp[x];
break;
}
if (i) i=nxt[i];
if (j) j=nxt[j];
}
}
}cout<<ans;
return 0;
}
代码来自 @mengnn。
C. Rock-String-Search 题解
题面及思路
这题还是很恶心的。
观察题面,简单的二维平面最短路径问题,但实际用 bfs 操做会有很多难点,于是...
因为石头的数量很少,所以我们可以爆搜!
对于每个石头都求最短路径,走到哪个取哪个直接暴力性质的 DFS+BFS 便可通过此题。
不是,这题都快被削成模拟题了。
时间复杂度
设一共有
于是,最终时间复杂度为
AC Code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
struct node{
int x,y;
int st,cnt;
};
int n,m,ans=-1;
int mp[N][N],sum=0;
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
bool vis[N][N];
inline void bfs(int sx,int sy,int st,int cnt){
if (cnt==sum){
ans=st;
return ;
}
queue<node> q;
q.push({sx,sy,st});
vis[sx][sy]=true;
while (!q.empty()){
node t=q.front();q.pop();
for (int i=0;i<4;i++){
int x=t.x+dx[i];
int y=t.y+dy[i];
if (x&&y&&x<=n&&y<=m&&mp[x][y]!=2&&!vis[x][y]){
if (mp[x][y]){
while (!q.empty()) q.pop();
mp[x][y]=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
vis[i][j]=false;
bfs(x,y,t.st+1,cnt+1);
return ;
}
q.push({x,y,t.st+1});
vis[x][y]=true;
}
}
}
}
int main(){
cin>>n>>m;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++){
cin>>mp[i][j];
sum+=(mp[i][j]==1);
}
if (mp[1][1]==2){
puts("-1");
return 0;
}
int k=mp[1][1];
if (k==1) mp[1][1]=0;
bfs(1,1,0,(k==1));
cout<<ans;
return 0;
}
代码来自 @mengnn。
D. Rock-String-Key 题解
题面及思路
时间复杂度
因为输入元素个数为
又因为用到了离散化和树状数组,所以它们各会取一个
总时间复杂度来到了
AC Code:
#include<bits/stdc++.h>
using namespace std;
int T;long long a,b;
int main(){
cin>>T;
while (T--){
cin>>a>>b;
while (__gcd(a,b)!=1) a=__gcd(a,b),b/=a;
if (b==1) puts("-1");
else cout<<b<<'\n';
}
return 0;
}
代码来自 @mengnn。
E. Rock-String-Run 题解
题面及思路
时间复杂度
AC Code:
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void rd(T &x){
x=0;T f=1;
char ch=getchar();
while (!isdigit(ch)){
if (ch=='-') f=-1;
ch=getchar();
}
while (isdigit(ch)){
x=(x<<3)+(x<<1)+(ch-'0');
ch=getchar();
}
x*=f;
}
inline __int128 af(__int128 x,__int128 y){
if (x>y) return x-y;
else return y-x;
}
int main(){
for (__int128 x=1,y=1;x&&y;rd(x),rd(y),puts(x&&y?(~af(x,y)&1?"We did it,we are best.":"Oh,no rock is lost."):""));
return 0;
}
代码来自 @mengnn。
F. Rock-String-Shop 题解
题面及思路
时间复杂度
AC Code:
#include<bits/stdc++.h>
using namespace std;
const int N=5e3+5;
const long long mod=1e9+7;
int n,k,a,b;
long long dp[N][N],s[N];
int main(){
cin>>n>>a>>b>>k;
if (abs(a-b)<2){
putchar('0');
return 0;
}
dp[0][a]=1;
for (int i=1;i<=k;i++){
for (int j=1;j<b;j++)
if (dp[i-1][j]){
int l=max(2*j-b+1,1);
int r=b-1;
dp[i][l]=(dp[i][l]+dp[i-1][j])%mod;
dp[i][j]=(dp[i][j]-dp[i-1][j])%mod;
dp[i][j+1]=(dp[i][j+1]+dp[i-1][j])%mod;
dp[i][r+1]=(dp[i][r+1]-dp[i-1][j])%mod;
}
for (int j=b+1;j<=n;j++)
if (dp[i-1][j]){
int l=b+1;
int r=min(2*j-b-1,n);
dp[i][l]=(dp[i][l]+dp[i-1][j])%mod;
dp[i][j]=(dp[i][j]-dp[i-1][j])%mod;
dp[i][j+1]=(dp[i][j+1]+dp[i-1][j])%mod;
dp[i][r+1]=(dp[i][r+1]-dp[i-1][j])%mod;
}
for (int j=1;j<=n;j++)
dp[i][j]=(dp[i][j-1]+dp[i][j])%mod;
}
long long ans=0;
for (int i=1;i<=n;i++)
ans=(ans+(dp[k][i]%mod+mod)%mod)%mod;
cout<<ans<<'\n';
return 0;
}
代码来自 @mengnn。