一,训练赛补题:1,Searching for Soulmates;2,Walking Home;二,cf round 789 div2补题:1, Tokitsukaze and Strange Inequality;三,acwing 提高课:acwing 188.武士风度的牛;acwing 173. 矩阵距离;
一,训练赛补题:
1,Searching for Soulmates
题意:给出两个数a,b,有如下操作:a*2,a/2,或者a+1,来使a==b,问最小的操作数;
思路:首先乘和除一定不会交替出现,因为会相互抵消掉的;所以一定有个分界点;
很容易想到分界点前后是先除后乘。
之后 如何运用乘和加来操作呢;
如下情况:
用f(x,y)表示使x和y相等的最小次数;
①:a>b 无解;
②:a*2>b,此时只能加法,return b-a;
③:b是奇数,return f(a,b-1)+1,解释:使a变成b-1,在加1次加法操作;(这个思想太6了);
④:b是偶数且a<=b/2,return f(a,b/2)+1,解释:使a变成b/2,所以前提是a<=b/2,然后进行一次乘法操作;
其实分界点在a<=b后是随机的,所以只要a<=b,对于每次的a,都设置一个分界点,去操作;
#include<bits/stdc++.h>
//#pragma GCC optimize(2)
#define rep1(i,a,n) for(ll i=a;i<n;i++)
#define rep2(i,a,n) for(ll i=a;i<=n;i++)
#define per1(i,n,a) for(ll i=n;i>a;i--)
#define per2(i,n,a) for(ll i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i,b) memset((a),(i),sizeof (b))
#define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
#define pb push_back
#define endl "\n"
#define lowbit(m) (-m&m)
#define yes cout<<"YES\n"
#define no cout<<"NO\n"
#define yi first
#define er second
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
ll a,b;
ll f(ll a,ll b)
{
if(a>b)return 1e18;
if(a*2>b)return b-a;
if(b%2)return f(a,b-1)+1;
if(b%2==0&&a<=b/2)return f(a,b/2)+1;
}
void solve()
{
cin>>a>>b;
ll c1=0;
if(a==b)cout<<0<<endl;
else
{
ll k=1e18;
while(a>1)
{
if(a<=b)
{
ll c2=f(a,b);
k=min(k,c1+c2);
}
if(a%2)a++;
else a/=2;
c1++;
}
cout<<k<<endl;
}
}
signed main()
{
quick_cin();
int T;
cin>>T;
while(T--)solve();
return 0;
}
2,walking home
题意:
给你一个n*n的矩阵,由'.'和'H'组成,带'H'的方格不可以走,牛在(1,1)只能向下和向右走,
且转向次数不超过k次,问到达(n,n)有几种方案;
思路:dfs+剪枝优化;
#include<bits/stdc++.h>
//#pragma GCC optimize(2)
#define rep1(i,a,n) for(ll i=a;i<n;i++)
#define rep2(i,a,n) for(ll i=a;i<=n;i++)
#define per1(i,n,a) for(ll i=n;i>a;i--)
#define per2(i,n,a) for(ll i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i,b) memset((a),(i),sizeof (b))
#define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
#define pb push_back
#define endl "\n"
#define lowbit(m) (-m&m)
#define yes cout<<"YES\n"
#define no cout<<"NO\n"
#define yi first
#define er second
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
const int N=1e2+10;
char a[N][N];
int st[N][N][5][5];
int n,k;
int dfs(int x,int y,int cs,int dir)
{
if(cs>k)return 0;
if(cs==k&&x!=n&&y!=n)return 0;
if(x>n||y>n)return 0;
if(x==n&&y==n) return 1;
int sum=0;
if(a[x][y]=='H')return 0;
if(dir)
{
sum+=dfs(x+1,y,cs,1);
sum+=dfs(x,y+1,cs+1,0);
}
else
{
sum+=dfs(x+1,y,cs+1,1);
sum+=dfs(x,y+1,cs,0);
}
return sum;
}
void solve()
{
cin>>n>>k;
rep2(i,1,n)
rep2(j,1,n)cin>>a[i][j];
cout<<dfs(2,1,0,1)+dfs(1,2,0,0)<<endl;
}
signed main()
{
quick_cin();
int T;
cin>>T;
while(T--)solve();
return 0;
}
二,cf 补题:
1,Tokitsukaze and Strange Inequality
题意:
给你一个长度为n的数组p,问有多少个本质不同的四元组(a,b,c,d)满足?
思路:枚举;
枚举的出发点很关键,从pc出发,每次统计出前边比pc小的pa的个数,在统计出满足pb>pd的个数;
可以用树状数组来优化求pa小于pc的个数;
固定pbpc,移动pd,更新pb>pd的个数,枚举得到的答案,所以不从不漏;
#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define rep1(i,a,n) for(ll i=a;i<n;++i)
#define rep2(i,a,n) for(ll i=a;i<=n;++i)
#define per1(i,n,a) for(ll i=n;i>a;i--)
#define per2(i,n,a) for(ll i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i,b) memset((a),(i),sizeof (b))
#define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
#define pb push_back
#define endl "\n"
#define lowbit(m) (-m&m)
#define yes cout<<"YES\n"
#define no cout<<"NO\n"
#define yi first
#define er second
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
const int N=1e4+10;
int c[N];
int n,a[N];
void add(int i,int d)
{
for(;i<=n;i+=lowbit(i))c[i]+=d;
}
int sum(int i)
{
int s=0;
for(;i>=1;i-=lowbit(i))s+=c[i];
return s;
}
void solve()
{
cin>>n;
memset(c,0,c);
rep2(i,1,n)cin>>a[i];
ll ans=0;
rep2(i,3,n)
{
add(a[i-2],1);
ll num=sum(a[i]);
rep2(j,i+1,n)
{
if(a[i-1]>a[j])ans+=num;
num+=sum(a[j]);
}
}
cout<<ans<<endl;
}
signed main()
{
quick_cin();
int T;
cin>>T;
while(T--)solve();
return 0;
}
三,
1,武士风度的牛;
题意:
思路:标准的bfs搜索,注意细节,判断下一步的地方不一定是a[i][j]=='.'才可以走,这样会把终点
'H'扔掉不走的!!,所以是a[i][j]!='*'才可以!;
if(x>0&&x<=n&&y>0&&y<=m&&a[x][y]!='*'&&st[x][y]==0)
#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define rep1(i,a,n) for(ll i=a;i<n;++i)
#define rep2(i,a,n) for(ll i=a;i<=n;++i)
#define per1(i,n,a) for(ll i=n;i>a;i--)
#define per2(i,n,a) for(ll i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i,b) memset((a),(i),sizeof (b))
#define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
#define pb push_back
#define endl "\n"
#define lowbit(m) (-m&m)
#define yes cout<<"YES\n"
#define no cout<<"NO\n"
#define yi first
#define er second
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
const int N=1e4+10;
int n,m;
char a[500][500];
int st[500][500];
int dist[500][500];
PII d[]={{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1}};
int sx,sy,edx,edy;
int bfs()
{
queue<PII>q;
q.push({sx,sy});
st[sx][sy]=1;
dist[sx][sy]=0;
while(q.size())
{
auto t=q.front();q.pop();
rep1(i,0,8)
{
int x=t.yi+d[i].yi,y=t.er+d[i].er;
if(x>0&&x<=n&&y>0&&y<=m&&a[x][y]!='*'&&st[x][y]==0)
{
st[x][y]=1;
q.push({x,y});
dist[x][y]=dist[t.yi][t.er]+1;
if(x==edx&&y==edy)return dist[x][y];
}
}
}
return dist[edx][edy];
}
signed main()
{
quick_cin();
cin>>m>>n;
rep2(i,1,n)
rep2(j,1,m)
{
cin>>a[i][j];
if(a[i][j]=='K')sx=i,sy=j;
if(a[i][j]=='H')edx=i,edy=j;
}
cout<<bfs();
return 0;
}
2,矩阵距离;
题意:
多源bfs;
其实就是起点变成了所以1的位置;然后把这些1都预先放进队列里;这样再去求各个位置的距离,由于bfs求到的一定是最短距离,所以某个位置的0被更新到的话,一定是距离它最近的1来更新的;
#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define rep1(i,a,n) for(ll i=a;i<n;++i)
#define rep2(i,a,n) for(ll i=a;i<=n;++i)
#define per1(i,n,a) for(ll i=n;i>a;i--)
#define per2(i,n,a) for(ll i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define memset(a,i,b) memset((a),(i),sizeof (b))
#define memcpy(a,i,b) memcpy((a),(i),sizeof (b))
#define pb push_back
#define endl "\n"
#define lowbit(m) (-m&m)
#define yes cout<<"YES\n"
#define no cout<<"NO\n"
#define yi first
#define er second
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
const int N=1e6+10;
PII q[N];
int n,m;
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
string s[1010];
int dist[1010][1010];
void bfs()
{
memset(dist,-1,dist);
int hh=0,tt=-1;
rep1(i,0,n)
rep1(j,0,m)
{
if(s[i][j]=='1')
{
q[++tt] = {i,j};
dist[i][j]=0;
}
}
while(hh<=tt)
{
auto t=q[hh++];
rep1(i,0,4)
{
int x=t.yi+dx[i],y=t.er+dy[i];
if(x<0||x>=n||y<0||y>=m)continue;
if(dist[x][y]!=-1)continue;
dist[x][y]=dist[t.yi][t.er]+1;
q[++tt] = {x,y};
}
}
}
signed main()
{
quick_cin();
cin>>n>>m;
rep1(i,0,n)cin>>s[i];
bfs();
rep1(i,0,n)
{
rep1(j,0,m)cout<<dist[i][j]<<" ";
cout<<endl;
}
return 0;
}