D.Go Stone Puzzle
原题链接:D - Go Stone Puzzle (atcoder.jp)
题目大意:
思路:
首先将能直接判断的情况单独处理,然后使用BFS处理剩下的情况。
直接判断的情况:
1.只有一块砖或者两块砖,这种情况下题目操作并不能改变什么,比较s与t即可;
2.如果s与t的同色砖数量不同,那么肯定不可能将s操作成t;
3.s==t,答案为0;
剩余情况通过BFS找出来,队列里存储二元组{当前字符串,操作次数},使用unordered——map标记字符串是否已经加入队列,暴力找出所有情况即可。
代码如下:
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int n;
string s,t;
queue<pair<string,int>> q; //{当前字符情况,当前操作次数}
unordered_map<string,int> v; //用于标记当前字符串情况是不是已经出现过
void bfs()
{
s+=" ";
t+=" "; //均补充两个空位
v[s]=1; //标记初始字符串情况为1
q.push({s,0}); //队列添加初始情况
while(q.size())
{
auto [ns,num]=q.front(); //取出当前字符串和操作次数
q.pop();
int pos;
for(int i=0;i<ns.size();i++)
{
if(ns[i]==' ')
{
pos=i; //找到第一个为空位
break;
}
}
for(int i=0;i<ns.size()-1;i++)
{
if(ns[i]!=' ' && ns[i+1]!=' ') //满足可操作的情况
{
string news=ns; //将当前字符串用另一个字符串存下
swap(news[i],news[pos]);
swap(news[i+1],news[pos+1]); //进行换位操作
if(news==t) //换位后成为t直接输出,程序结束
{
cout<<num+1<<endl;
return ;
}
if(v[news]) //如果已经标记过则跳过,否则标记,加入队列;
continue;
v[news]=1;
q.push({news,num+1});
}
}
}
cout<<-1<<endl; //搜完所有情况无法变成t,输出-1;
}
void slove()
{
cin>>n>>s>>t;
if(s.size()==1 || s.size()==2)
if(s!=t) //如果只有一块砖或者两块砖无法变换形式,s!=t直接输出-1;
{
cout<<-1<<endl;
return ;
}
int ans1=0,ans2=0; //记录白砖数量
for(int i=0;i<s.size();i++)
{
if(s[i]=='w')
ans1++;
if(t[i]=='w')
ans2++;
}
if(ans1!=ans2) //同色砖数量不同必然不能操作成功
{
cout<<-1<<endl;
return ;
}
if(s==t) //不需要操作
{
cout<<0<<endl;
return ;
}
bfs(); //广搜剩下的情况
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
//cin>>_;
while(_--)
{
slove();
}
return 0;
}
E - Tree and Hamilton Path 2
原题链接:E - Tree and Hamilton Path 2 (atcoder.jp)
题意:
知识点:树的直径
思路: 要走完所有的城市,必然会有一些路要走两遍,最后结果就是(所有的路总长)*2-只走一边的长度。所以要使距离最短就是使起点到终点的无重复路径最长。所以这个题目将图想象成树,只要求出树的直径就好。可以通过两遍dfs或者dfs+dp来解决,我这里先只写两遍dfs的解法。
代码:
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int n,s,sum; //n为城市数,s为找到的起点和终点,sum为两倍的所有边的权重
vector<pair<int,int>> e[200005]; //邻接矩阵存储边的信息{终点,权重}
int dep[200005]; //从起点到该点的最长距离
void dfs(int st,int ed)
{
if(dep[ed]>dep[s]) //当前距离长度大于起点长度,更新起点;
s=ed;
for(int i=0;i<e[ed].size();i++) //遍历子节点;
{
int x=e[ed][i].first;
int y=e[ed][i].second;
if(x!=st)
{
dep[x]=dep[ed]+y; //更新子节点长度
dfs(ed,x);
}
}
}
void slove()
{
cin>>n;
for(int i=1;i<n;i++)
{
int a,b,c;
cin>>a>>b>>c;
e[a].push_back({b,c});
e[b].push_back({a,c}); //无向图存两遍
sum+=2*c;
}
dfs(0,1); //第一遍用于找到最深的叶子节点作为起点;
dep[s] = 0;
dfs(0,s); //第二遍用于找到离起点最远的叶子节点;
cout << sum-dep[s] << endl;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
//cin>>_;
while(_--)
{
slove();
}
return 0;
}
F . x = a^b
题目大意:
思路:刚开始就写的暴力,然后直接超时,因为要枚举到,复杂度太大会超时,然后将指数b分为两个部分, b=2和b>=3。当b=2时,那么x的数量就为,即为所有的完全平方数。再考虑b=3的部分,直接枚举到,然后用map去将每一个x进行标记,避免重复计数。再通过判断该数是否为完全平方数,如果是,也计数下来,因为如果他是完全平方数则属于b=2的一部分,后续计算避免进行去重。最后计算即(b=2的x数量) + (b>=3的x数量)- (b>=3时记录的完全平方数的数量)。
代码:
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
map<int , bool> mp;
void slove()
{
int n,ans=0,num=0;
cin>>n;
for(int i=2;i*i*i<=n;i++) //从2开始枚举,先忽略a=1的情况
{
int x=i*i;
while(x<=n/i)
{
x*=i;
if(mp[x]) //已标记过
continue;
if((int)sqrtl(x)*sqrtl(x)==x)
num++; //b>=3时的完全平方数
mp[x]=1; //标记
ans++; //b>=3所有的x数量
}
}
cout<<(int)sqrtl(n)+ans-num<<endl; //b=2时的sqrtl(n)包含1
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
//cin>>_;
while(_--)
{
slove();
}
return 0;
}