秒懂算法1

欢迎交流,有什么问题,还请指出!!!

目录

欢迎交流,有什么问题,还请指出!!!

P1002 [NOIP2002 普及组] 过河卒

原题链接 : 

思路 : 

代码 : 

A (自己写的,aaa):

 B(EK的代码) : 

例题推荐 : 

P1003 [NOIP2011 提高组] 铺地毯

原题链接 : 

 [NOIP2011 提高组] 铺地毯 - 洛谷

思路 : 

代码 : 

P1008 [NOIP1998 普及组] 三连击

原题链接 : 

思路 :

代码 :

 P1028 [NOIP2001 普及组] 数的计算

原题链接 : 

思路 : 

代码 : 

P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题

原题链接 : 

思路 : 

代码 : 


P1002 [NOIP2002 普及组] 过河卒

原题链接 : 

[NOIP2002 普及组] 过河卒 - 洛谷

思路 : 

一道很典型的线性dp问题,应该可以归类于三角形dp问题。

每个点能由其上方的点走下来,也能由左边的点走过来,故到点S(i,j)的方案数等于S(i-1,j)+S(i,j-1),所以动态转移方程 : dp[i][j] = dp[i-1][j] + dp[i][j-1];

本题要注意的是 :

  • 一定要加long long(十年oi一场空,不开long long 见祖宗!!!),不然可能就只过1,2,5,然后还找不到代码哪里有问题,hhh;
  • 马所在的点(x,y)和马能一步走到的点(p,r)((p-x)^2+(r-y)^2==5)都是一个陷阱,不能经过,也就是到该点路线数为0;

然后请看代码 : 

代码 : 

A (自己写的,aaa):

#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;}
const int N = 1e5+10;
int n,m,x,y;
LL a[25][25] = {0},dp[25][25] = {0};

inline void solve(){
	cin>>n>>m>>x>>y;
	n++;m++;x++;y++;
	a[x][y] = 1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if( (pow(i-x,2)+pow(j-y,2)) == 5)
				a[i][j] = 1;
	dp[1][1] = 0;
	for(int i=2;i<=n;i++){
		if(a[i][1]==1) break;
		else 	dp[i][1] = 1;
	}
	for(int j=2;j<=m;j++){
		if(a[1][j] == 1) break;
		else 	dp[1][j] = 1;
	} 
	for(int i=2;i<=n;i++){
		for(int j=2;j<=m;j++){
			if(a[i][j] == 1) dp[i][j] = 0;
			else dp[i][j] = dp[i-1][j] + dp[i][j-1];
		}
	}
// 测试代码
//	for(int i=1;i<=n;i++){
//		for(int j=1;j<=m;j++){
//			cout << dp[i][j] << " ";
//		}
//		cout << endl;
//	}
	cout << dp[n][m];
}
 
int main()
{
    IOS
    int _;
    // cin >> _;
    _ = 1; 
    while(_ --) solve();
    return 0;
}

 B(EK的代码) : 

这里用到了一个bitset来记录马点以及马一步能到的点的状态为true,较代码A,能节省不少空间。

#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;}
const int N = 30;
int n,m,x,y;

LL dp[25][25] = {0};

bitset<N> mp[N];

int dx[8] = {1,1,-1,-1,2,2,-2,-2};
int dy[8] = {2,-2,2,-2,1,-1,1,-1};

inline void solve(){
	cin>>n>>m>>x>>y;
	n++;m++;x++;y++;
	for(int i=0;i<8;i++){
		int nx = x + dx[i],ny = y + dy[i];
		if(1<=nx&&nx<=n&&1<=ny&&ny<=m) mp[nx][ny] = true;
	}
	mp[x][y] = true;
	dp[1][1] = 1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(i==1&&j==1) continue;
			dp[i][j] = dp[i-1][j] + dp[i][j-1];
			if(mp[i][j]) dp[i][j] = 0;
		}
	}
	cout << dp[n][m] << endl;
	return ;
}
 
int main()
{
    IOS
    int _;
    // cin >> _;
    _ = 1; 
    while(_ --) solve();
    return 0;
}

例题推荐 : 

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

P1003 [NOIP2011 提高组] 铺地毯

原题链接 : 

 [NOIP2011 提高组] 铺地毯 - 洛谷

思路 : 

使用结构体存储每个地毯的a,b,g,k的信息,因为从小到大,所以从后往前遍历,找到第一个地毯(x,y)在其范围内的输出其编号即可!!!

代码 : 

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
struct node{
	int a,b,g,k;
}d[N];
int n,x,y;

int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>d[i].a>>d[i].b>>d[i].g>>d[i].k;
	cin>>x>>y;
	int ans = 0;
	for(int i=n;i>=1;--i){
		if(x>=d[i].a&&x<=d[i].a+d[i].g && y>=d[i].b&&y<=d[i].b+d[i].k){
			ans = i;
			break;
		}
	}
	cout << ans << endl;
}

P1008 [NOIP1998 普及组] 三连击

原题链接 : 

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

思路 :

直接暴力枚举即可,值得注意的是Ek是直接枚举的三位数,也就是(100,1000),但是仔细想一下,真正的范围应该在(123,333);

代码 :

(很久以前写的c代码,hh)

#include <stdio.h>
int main()
{
    int a,b,c;
    for(a=123;a<=333;a++)
            {
                b=a*2;
                c=a*3;
                if((a/100+a/10%10+a%10+b/100+b/10%10+b%10+c/100+c/10%10+c%10==1+2+3+4+5+6+7+8+9)&&((a/100)*(a/10%10)*(a%10)*(b/100)*(b/10%10)*(b%10)*(c/100)*(c/10%10)*(c%10)==(1)*(2)*(3)*(4)*(5)*(6)*(7)*(8)*(9)))
                    printf("%d %d %d\n",a,b,c);
            }
    return 0;
}

 P1028 [NOIP2001 普及组] 数的计算

原题链接 : 

[NOIP2001 普及组] 数的计算 - 洛谷

思路 : 

后缀和 + 动态规划

设状态dp[i][j]表示长度为i且最后一位数值为j的方法数量,容易得到状态转移方程:

dp[i][j] = Sum(dp[i-1][k])<k=2j,n>

右边这个式子是可以通过后缀和处理出来的。

最后的答案就是将整个dp数组求和

代码 : 

#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;}
const int N = 1e3+10;
LL dp[N][N],sf[N],ans;
int n;

inline void solve(){
	cin>>n;
	dp[1][n] = 1;
	for(int i=1;i<=n;i++) sf[i] = 1;
	
	for(int i=2;i<=n;i++){
		for(int j=1;j<=n/2;j++){
			dp[i][j] = sf[2*j];
		}
		for(int j=n;j>=1;j--) sf[j] = sf[j+1] + dp[i][j];
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			ans += dp[i][j];
	cout << ans << '\n';
	return ;
}
 
int main()
{
    IOS
    int _;
    // cin >> _;
    _ = 1; 
    while(_ --) solve();
    return 0;
}

P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题

原题链接 : 

[NOIP2001 普及组] 最大公约数和最小公倍数问题 - 洛谷

思路 : 

枚举 + gcd() + lcm(),这题主要考察的是你怎么求gcd()和lcm(),也就是最小公倍数,和最大公约数,

我的求法 : 

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); }

Ek的求法 : 

LL gcd(LL a,LL b){ return b==0 ? a : gcd(b,a%b); }
LL lcm(LL a,LL b){ return a / gcd(a,b) * b ; }

本质一样,原理相同!!!

这题可以利用lcm和gcd的性质将二维的时间复杂度优化到一维,

gcd(a,b) = x && lcm(a,b)=y,那么x*y/a = b;!!!

代码 : 

#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;
LL gcd(LL a,LL b){ return b==0 ? a : gcd(b,a%b); }
LL lcm(LL a,LL b){ return a / gcd(a,b) * 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;}
const int N = 2e5+10;
int x,y;
LL ans;

inline void solve(){
	cin>>x>>y;
	for(int i=x;i<=y;i++){
		int j = x*y/i;
		if(gcd(i,j)==x&&lcm(i,j)==y) ans ++;
	}
	cout<<ans<<endl;
}
 
int main()
{
    IOS
    int _;
    // cin >> _;
    _ = 1; 
    while(_ --) solve();
    return 0;
}

猜你喜欢

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