1,K倍区间2,bfs保存最短路径
1,K倍区间
讲一讲做题流程:
首先先去想暴力该怎么做:
3层for循环,第一层控制r,第二层控制l,第三层求r到l的和,然后看sum%k==0 ,相等ans++,不等无操作,所以基本上复杂度是O(n^3);那数据范围是1e5,所以3次方就是1e15,肯定过不了,那就去想优化;
知道暴力怎么做后,再去想可以优化的地方:
首先容易想到的就是第三层循环求和,我们可以预处理前缀和,用前缀和去做,这样求和的操作就是O(1),所以时间复杂度降为O(n^2),1e10,能过掉一般的数据了应该;但是一个简单的前缀和优化这还不够,深一点的优化总要和题目性质挂个勾
#include<bits/stdc++.h>
#define rep1(i,a,n) for(int i=a;i<n;i++)
#define rep2(i,a,n) for(int i=a;i<=n;i++)
#define per1(i,n,a) for(int i=n;i>a;i--)
#define per2(i,n,a) for(int i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
int n,k;
const int N=1e5+10;
ll s[N];
int cnt[N];
int main()
{
quick_cin();
cin>>n>>k;
rep2(i,1,n)
{
int x;cin>>x;
s[i]=s[i-1]+x;
}
ll ans=0;
cnt[0]=1;
rep2(i,1,n)
{
ans+=cnt[s[i]%k];
cnt[s[i]%k]++;
}
cout<<ans;
return 0;
}
2,bfs储存最短路径
题意:如果有最短路径,打印最短路径,如果到不了终点,输出NO,
不同于一般的求最短路长度,这次我们还需要把路径表示出来,how?
如果我们想在bfs遍历过程中想方法去存储,我感觉难办,因为无法确定每次到的要存储哪一个点,都存储了,哪个点是最短路上的点呢?
这时候就需要一个确定状态的点,是哪个点呢?
就是每次用该点去遍历其他地方的点,也就是每次取得队头的点,我们用它来取四个方向找点,所以4个方向的点都和它有关,我们就去存储这个点,这样就可以得到一种”父子“关系;每次得到的新点都指向它的父节点,类似于树;这样一般bfs()完后,就得到了一个指向关系;因为要找的是最短路,我们可以确定了终点,只要从终点回溯,一直往前找父节点,这样就能找到起点;海能确保是最短路,因为就是从终点出发的;
所以正着一遍bfs,然后再回溯一遍树,即可得到最短路径;
回溯:注意细节;
void getpath()
{
int i=n-2,j=n-2;
stack<PII>ans;
while(hs[i][j].first!=0&&hs[i][j].second!=0)
{
ans.push({i,j});
int x=hs[i][j].first;//一定先用x,y存储,直接i=hs[i][j].first,
//会影响j=hs[i][j].second,因为i改变了;
int y=hs[i][j].second;
i=x;
j=y;
}
ans.push({1,1});//(1,1)不会被存进去,手动push
while(ans.size())
{
auto t=ans.top();
ans.pop();
printf("(%d,%d)",t.first,t.second);
}
}
代码;
#include<bits/stdc++.h>
#define rep1(i,a,n) for(int i=a;i<n;i++)
#define rep2(i,a,n) for(int i=a;i<=n;i++)
#define per1(i,n,a) for(int i=n;i>a;i--)
#define per2(i,n,a) for(int i=n;i>=a;i--)
#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef double db;
int n;
int maze[1010][1001];
int f[101][101];
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
PII hs[101][101];
bool flag=0;
void bfs()
{
memset(f,-1,sizeof f);
queue<PII>q;
f[1][1]=0;
q.push({1,1});
while(q.size())
{
auto t=q.front();q.pop();
if(t.first==n-2&&t.second==n-2)
{
flag=1;
break;
}
rep2(i,0,3)
{
int x=t.first+dx[i],y=t.second+dy[i];
if(x>0&&x<n-1&&y>0&&y<n-1&&maze[x][y]==0&&f[x][y]==-1)
{
q.push({x,y});
hs[x][y] ={t.first,t.second};
f[x][y]=f[t.first][t.second]+1;
}
}
}
}
void getpath()
{
int i=n-2,j=n-2;
stack<PII>ans;
while(hs[i][j].first!=0&&hs[i][j].second!=0)
{
ans.push({i,j});
int x=hs[i][j].first;
int y=hs[i][j].second;
i=x;
j=y;
}
ans.push({1,1});
while(ans.size())
{
auto t=ans.top();
ans.pop();
printf("(%d,%d)",t.first,t.second);
}
}
int main()
{
quick_cin();
cin>>n;
rep2(i,0,n-1)
rep2(j,0,n-1)cin>>maze[i][j];
bfs();
if(flag)getpath();
else printf("NO");
return 0;
}