秒懂算法三

目录

1147 连续自然数和

原题链接 : 

思路1 : (按照EK的讲解,hh) 

求因子算法模板 : 

代码 1 (数学): 

思路 2(暴力) :

代码2(暴力) : 

P1125 [NOIP2008 提高组] 笨小猴

原题链接 : 

思路 : 

试除法判断质数算法模板 : 

代码 : 

P1605 迷宫

原题链接 : 

思路 : 

代码 : 

P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G

原题链接 : 

思路 : 

代码 : 

 P1037 [NOIP2002 普及组] 产生数

原题链接 : 

思路 : 

代码 : 


视频链接 : 秒懂算法三

1147 连续自然数和

原题链接 : 

连续自然数和 - 洛谷

思路1 : (按照EK的讲解,hh) 

  • 题意 : 在1-m的序列中找连续的一段序列[l,r],要求满足sum([l,r]) = m;
  • 那么就容易想到等差数列的求和公式,sum = (l+r)*(r-l+1)/2;
  • 对于题目也就是 : (l+r) * (r-l+1) = 2*m;
  • 那么也就是找2*m的两个因子 (x1,x2) : x1 = (l+r),x2  = (r-l+1);
  • 对于上面的式子有 : r = (x1+x2-1)/2,l =x1=r;
  • 最后满足 0<=l && l<=r && (l+r)*(r-l+1) == 2*m之后,就可以将l,r添加到答案ans中
  • 对ans进行排序之后,最后输出ans即可

求因子算法模板 : 

对于这种思路,一个重要的点是求2*m的所有因子,下面贴上求x的所有因子的代码 : 

vector<int> get_divisors(int x){
    vector<int> res;
    for (int i = 1; i <= x / i; i ++ )
        if (x % i == 0){
            res.push_back(i);
            if (i != x / i) res.push_back(x / i);
        }
    sort(res.begin(),res.end());
    return res;
}

代码 1 (数学): 

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;
typedef long long LL;
int gcd(int a,int b){ return b==0 ? a : gcd(b,a%b); }
int lcm(int a,int b){ if(a==0||b==0) return 0; return (a*b)/gcd(a,b); }
bool is_prime(int x){if(x<2) return false;
for(int i=2;i<=x/i;i++) if(x%i==0) return false; return true;}
vector<int> get_divisors(int x){
    vector<int> res;
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0){
            res.push_back(i);
            if (i != x / i) res.push_back(x / i);
        }
    sort(res.begin(),res.end());
    return res;
}
const int N = 2e5+10;
int m;

inline void solve(){
	cin>>m;
	vector<int> div;
	div = get_divisors(2*m);
	int l , r;
	// sum([l,r]) == m   ->  (l+r)*(r-l+1) = 2*m;
	// 2*m的两个因子 : 
	// 	x1 : (l+r)   x2 : (r-l+1)
	// 则 : l = x1 - r   r = (x1 + x2 - 1)/2;
	vector<pair<int,int>> ans;
	for(auto& x1 : div){
		for(auto& x2 : div){
			if( (x1 +x2-1) % 2 ) continue;
			int r = (x1 + x2 -1)/2;
			int l = x1 - r;
			if(0<=l && l<=r && (l+r)*(r-l+1) == 2*m ){
				ans.push_back({l,r});
			}
		}
	}
	sort(ans.begin(),ans.end());
	for(const auto &pair : ans){
		cout << pair.first << " " << pair.second <<endl;
	}
	return ;
}
 
int main()
{
    IOS
    int _;
    // cin >> _;
    _ = 1; 
    while(_ --) solve();
    return 0;
}

思路 2(暴力) :

数据不算大,直接暴力即可,一遍遍历,1e3左右

代码2(暴力) : 

#include<bits/stdc++.h>
using namespace std;
int m,sum;
int main(){
	cin>>m;
	for(int i=1;i<=m/2;i++){
		sum = i;
		for(int j=i+1;j<m;j++){
			sum += j;
			if(sum==m) cout << i << " " <<j<<endl;
			else if(sum>m){	break; }
		}
	}
}

P1125 [NOIP2008 提高组] 笨小猴

原题链接 : 

[NOIP2008 提高组] 笨小猴 - 洛谷

思路 : 

  • 哈希表  : 用size = 26的数组z来模拟哈希表,存字符串s中出现各字母的次数
  • 判断质数 : 本题重要的一点是如何判断质数,下面将附上试除法判断质数的算法模板;

试除法判断质数算法模板 : 

bool is_prime(int x)  //判定质数 
{
	if(x<2) return false;
	for(int i=2;i<=x/i;i++)
	    if(x%i==0) 
	       return false;
	return true;
}

代码 : 

#include<bits/stdc++.h>
using namespace std;

bool is_prime(int x)  //判定质数 
{
	if(x<2) return false;
	for(int i=2;i<=x/i;i++)
	    if(x%i==0) 
	       return false;
	return true;
}

int main()
{
	string s;
	cin>>s;
	int n=s.size();
    int z[26]={0};
    for(int i=0;i<n;i++)	z[int(s[i]-'a')]++;
	int maxn=-1,minn=101;
	for(int i=0;i<26;i++)
		if(z[i]>maxn)
		   	maxn=z[i];
		else if(z[i]<minn&&z[i]!=0)
		   	 minn=z[i];
	int k=maxn-minn;
	if(is_prime(k))
	   {
	   	  cout<<"Lucky Word"<<endl;
	     cout<<(maxn-minn); 
	   }
	   else
	   {
	   	 cout<<"No Answer"<<endl;
	     cout<<0; 
	   }
  return 0;
}

P1605 迷宫

原题链接 : 

迷宫 - 洛谷

思路 : 

一道dfs模板题,注意细节即可,思路在代码里!!!

代码 : 

#include<bits/stdc++.h>
using namespace std;
const int N = 100;
int sx,sy,fx,fy,n,m,t,sum;
int a[N][N];
void dfs(int x,int y){
	if(x==fx && y==fy){  sum++ ; return ; }//到达终点 
	if(a[x][y]==0||a[x][y]==2) return ;//遇到障碍或走过 
	
	a[x][y] = 2;//标记走过 
	dfs(x+1,y);//右 
	dfs(x-1,y);//左 
	dfs(x,y+1);//下 
	dfs(x,y-1);//上 
	a[x][y]=1;//还原现场 
}
int main()
{
	cin>>n>>m>>t;
	cin>>sx>>sy>>fx>>fy;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			a[i][j] = 1;//可以走 
	for(int i=1;i<=t;i++){
		int x,y;cin>>x>>y;
		a[x][y] = 0;//0表示障碍物 
	}
	if(a[fx][fy]==0){//终点是障碍物 
		 cout<<0<<endl;
		 return 0;
	}
	dfs(sx,sy);//dfs
	cout<<sum<<endl;
	return 0;
}

P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G

原题链接 : 

[NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G - 洛谷s

思路 : 

使用优先队列,每次优先合并较小的两堆果子。

代码 : 

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e4+10;
LL ans,n,x,a,b;

int main()
{
	cin>>n;
	priority_queue<int,vector<int>,greater<int>> pq;
	for(int i=1;i<=n;i++){
		cin>>x;
		pq.push(x);
	}
	while(pq.size()>1){
		a = pq.top();pq.pop();
		b = pq.top();pq.pop();
		
		ans += a+b;
		pq.push(a+b);
	}
	cout<<ans<<endl;
	return 0;
}

 P1037 [NOIP2002 普及组] 产生数

原题链接 : 

https://www.luogu.com.cn/problem/P1037

思路 : 

图 + dfs;

代码 : 

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 15;
string s;
int k;
vector<int> g[N];
int cnt[N];
bitset<N> vis;
void dfs(int x){
	vis[x] = true;
	for(const auto &y : g[x]){
		if(!vis[y]) dfs(y);
	}
}

void output(__int128 x){
	if(x/10) output(x/10);
	putchar(x%10+'0');
}

int main()
{
	cin>>s>>k;
	for(int i=1;i<=k;i++){
		int x,y;cin>>x>>y;
		g[x].push_back(y);
	}
	for(int i=0;i<=9;i++){
		vis.reset();
		dfs(i);
		cnt[i] = vis.count();
	}
	__int128 ans = 1;
	for(const auto &i : s){
		ans *= cnt[i-'0'];
	}
	output(ans);
	return 0;
}

欢迎交流和指出问题!!!

猜你喜欢

转载自blog.csdn.net/ros275229/article/details/132584274
今日推荐