重庆城市科技学院第十三届重庆程序设计竞赛选拔赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ
A.好数对
链接:https://ac.nowcoder.com/acm/contest/108648/A
给你一个整数数组 a。
如果一组数字 (i,j) 满足 a[i] = a[j] 且 i < j ,就可以认为这是一组 好数对 。
核心思想:如果有两个及以上那么便可以组成好数对,那么直接用map存一下每个数的个数,然后用组合数的公式c(n,2),也就是n*(n-1)/2,然后用ans把所有的加起来就可以过了
void moon()
{
int n;
cin>>n;
map<int,int>mp;
for(int i=1;i<=n;i++){
int x;
cin>>x;
mp[x]++;
}
int ans=0;
for(auto [y,x]:mp){
if(x>=2){
// cout<<x<<'\n';
ans+=((x-1)*x)/2;
// cout<<ans<<'\n';
}
}
cout<<ans<<'\n';
}
B.NB Prime
https://ac.nowcoder.com/acm/contest/108648/B
已知正整数 n 是两个**不同的质数的乘积**,试求出两者中较大的那个质数
核心思想:题目直接说明了这个n是由两个质数的乘积,那么我们直接从后往前找到第一个能被整除的数输出即可
```
void moon()
{
int n;
cin>>n;
for(int i=n-1;i>=2;i--){
if(n%i==0)return cout<<i<<'\n',void();
}
}
```
C.迷宫问题
https://ac.nowcoder.com/acm/contest/108648/C
核心思想:这个我们只需要跑两遍dfs(深度优先搜索),或者用bfs(广度优先搜索)跑一边迷宫即可
特别注意这题的数据范围
首先我们用vector开一个string数组,这里也是卡了很多人,因为你如果开全局变量的话由可能n=2e5,m=1,也有可能**n=1,m=2e5**
所有这里如果不用vector在内部开数组的话肯定会被卡内存的
还有的人会问在全局开一个vector<string>g[N+1];可以吗,答案是**不行的**
如果你这样开的话会出现一种情况放不下,m=2e5,那么你此时的数组占用就是一个**2e5*2e5=4e10**的内存,这是我们不能接受的
**dfs**(深搜):**记得打标记!!!**
**深搜的思路**:就是先跑一遍dfs,把整个迷宫遍历一遍,如果有出口那么直接输出YES
如果在搜图的过程中碰见了K(钥匙),那么打个标记ok=1
第二次深搜(主要是为了那种第一次遇见D(门)但是没有钥匙的情况)
那么你此时只能先第一次把钥匙拿了,再跑一边dfs才能成功走到终点
```
void moon()
{
int n,m,ok=0;
cin>>n>>m;
vector<string>s(n);
vector vis(n,vector<int>(m));
for(int i=0;i<n;i++)cin>>s[i];
auto dfs=[&](auto self,int x,int y,int &ok)->void{
if(x==n-1&&y==m-1){
cout<<"YES"<<endl;
exit(0);
}
for(int i=0;i<4;i++){
int nx=x+dx[i],ny=y+dy[i];
if(nx<0||nx>=n||ny<0||ny>=m||s[nx][ny]=='#')continue;
if(vis[nx][ny])continue;
if(ok==0&&s[nx][ny]=='D')continue;
if(s[nx][ny]=='K')ok=1;
vis[nx][ny]=1;
self(self,nx,ny,ok);
}
};
dfs(dfs,0,0,ok);
for(int i=0;i<n;i++){
for(int j=0;j<m;j++)vis[i][j]=0;
}
dfs(dfs,0,0,ok);
cout<<"NO\n";
}
```
**bfs**
**广搜的思路**:
直接bfs跑一遍即可解决,只需要在搜索途中**打标记**,还有如果你在**搜索途中遇见了K**,记得把**标记全部清一遍**,相当于以K这个点的位置又开一次bfs(广搜)
```
void moon()
{
int n,m;
cin>>n>>m;
vector<string>s(n);
for(int i=0;i<n;i++)cin>>s[i];
queue<pll>q;
q.emplace(0,0);
vector vis(n,vector<bool>(m));
int ok=0;
bool flag=true;
while(q.size()){
auto [x,y]=q.front();q.pop();
for(int i=0;i<4;i++){
int nx=x+dx[i],ny=y+dy[i];
if(nx<0||nx>=n||ny<0||ny>=m)continue;
if(s[nx][ny]=='#')continue;
if(s[nx][ny]=='D'&&ok==0)continue;
if(s[nx][ny]=='K'&&ok==0){
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
vis[i][j]=0;
}
}
ok=1;
}
if(vis[nx][ny])continue;
vis[nx][ny]=1;
q.emplace(nx,ny);
}
}
cout<<(vis[n-1][m-1]==1?"YES":"NO");
}
```
D. 谁改了我的键位
**核心思路**:这题也是直接map存一下就过了(**我只能感叹一句STL真好用**),我们先用map把每个字母出现的次数统计一下,然后把这些个数全部放进a数组中(**主要是想用sort**)进行一个从大到小排序
然后把相邻的两个数相减即可
```
void moon()
{
string s;
int n;
cin>>n>>s;
map<char,int>mp;
for(int i=0;i<s.size();i++){
mp[s[i]]++;
}
vector<int>a;
for(auto [c,x]:mp){
a.push_back(x);
}
sort(a.begin(),a.end(),greater<int>());
int t=a.size();
int ans=0;
if(t==1)ans+=a[0];
if(t>=2)ans+=a[0]-a[1];
if(t==3)ans+=a[2];
if(t>=4)ans+=a[2]-a[3];
cout<<ans<<'\n';
}
```
E. MJ哥哥的质数
**核心思路**:你只需要注意他是拆解成质因子(也就是所有因数都是质数),那么假设我的m是一个质因子全是2的便是最小的那种情况了,总所周知2是最小的质数,那么全是2组成的数一定是m最小的情况,如果n比这种m还小那就只能输出NO
```
void moon()
{
int n,ans=0;
cin>>n;
int t=n;
for(int i=2;i*i<=n;i++){
while(n%i==0)ans++,n/=i;
}
if(n!=1)ans++;
int m=pow(2,ans+1);
cout<<(m<t?"YES":"NO")<<'\n';
}
```
F.丢手绢
这题你别看他这么大一堆,有用的就一句话,假设你在i这个位置,丢手绢的话你要么丢在i+1,要么就丢在i+2的位置,然后用dp跑一遍就过了
**核心思路**:竟然已经想到用dp了,那么我们需要推一下状态转移方程
首先我们下一次丢手绢的位置只能是**i+1或者i+2**,那么我们此时是由那个状态转移过来的呢???
很显然就是**min(dp[i-1],dp[i-2])+a[i]**,前两个位置中最小的那一个加上丢在当前这个位置的生气值
```
void moon()
{
int n;
cin>>n;
vector<int>a(n+1),dp(n+1);
for(int i=0;i<n;i++)cin>>a[i];
dp[0]=a[0],dp[1]=a[1];
for(int i=2;i<=n;i++){
dp[i]=a[i]+min(dp[i-1],dp[i-2]);
}
cout<<dp[n]<<'\n';
}
```
G.奈何桥
**核心思路**:拓扑排序加上dp求最短路即可
这题也可以用dijkstra(毕竟这个边权并不为负值)
**拓扑排序加dp求最短路**
首先我们用邻接表把图存下来,然后我们需要把**除了1以外入度为0的点筛掉**(因为我们不筛的话,求的就**不一定是1到x的最短路**了,有可能会求到某个入度为0的点到x的路径),然后判断每次输入的黑边(0)和白边(1)的边权
状态转移方程就是**dp[son]=min(dp[son],dp[fa]+w?b:a);**
**特别注意** :每次的dp都得重新赋值
```
void moon()
{
int n,m;
cin>>n>>m;
vector<pll>g[n+1];
vector<int>in(n+1);
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
g[u].push_back({v,w});
in[v]++;
}
queue<int>q;
for(int i=2;i<=n;i++)if(in[i]==0)q.emplace(i);
while(q.size()){
auto u=q.front();q.pop();
for(auto [v,w]:g[u]){
in[v]--;
if(in[v]==0)q.emplace(v);
}
}
int k;
cin>>k;
while(k--){
int a,b,x;
cin>>a>>b>>x;
vector<int>dp(n+1,0x3f3f3f3f);
vector<int>in1=in;
dp[1]=0;
q.emplace(1);
while(q.size()){
auto u=q.front();
q.pop();
for(auto [v,w]:g[u]){
in1[v]--;
if(in1[v]==0)q.emplace(v);
if(w==0){
dp[v]=min(dp[v],dp[u]+a);
}
else dp[v]=min(dp[v],dp[u]+b);
}
}
cout<<dp[x]<<'\n';
}
}
```