蓝桥杯刷题日记DAY18

蓝桥杯刷题日记DAY18,第1张

目录

1.蓝桥幼儿园

2.找素数

 3.优秀的拆分

 4.蓝肽子序列

5.包子凑数


1.蓝桥幼儿园

 

解题思路,这题考察的是并查集,并查集模板题。


#include
using namespace std;
const int N =200010;
int n,m;
int p[N];//FATHER 数组存每个元素的父节点是谁,
int find(int x)//返回x的祖宗节点+路径压缩
{
         if(p[x]!=x) p[x]=find(p[x]);//如果x不是根节点的话,我们就让他的父节点等于他的祖宗节点
     return p[x];//返回他的父节点

}

int main()
{
  scanf("%d%d",&n,&m);
   for(int i=1;i<=n;i++)p[i]=i;
while( m--)
{
   
int op, a,b;
scanf("%d%d%d",&op,&a,&b);
if(op==1)p[find(a)]= find(b);
else
{
   if(find(a) == find(b)) cout<<"YES"<
2.找素数

 题解:直接暴力筛素数,

#include
using namespace std;
bool is_prime(int n)
{
    for(int i=2;i<=sqrt(n);i++)
    {
        if(n%i==0)
        {
            return 0;
        }
    }
    return 1;
}
int main()
{
    int cnt=0,sum=1;
    while(cnt!=100002)
    {
        sum++;
        if(is_prime(sum))
        {
            cnt++;
        }
    }
    cout<
 3.优秀的拆分

这题考察的是位运算。


#include
using namespace std;
int main()
{
    long long n;
    cin>>n;
    if(n&1)//把n的最后一位判断是否=1,如果等于1则不存在
    {
        cout<<"-1"<0;i--)
        {
          if((n>>i)&1)//把n右移i位,然后再与1,如果等于一说明该拆分方案成立
          {
            cout<<(int)pow(2,i)<<" ";//pow函数默认返回值为double类型,求的是2^i
          }
        }
    
    return 0;
}

 4.蓝肽子序列

题解思路:这题就是变种的最长公共子序列,用dp做,注意这题每个蓝肽的首字母都是大写,然后后面都是小写,用两个数组分别存储a和b的子序列,然后再用dp。


f[N][N]代表的是a的前i个字母和b的前j个字母的最长公共子序列的长度,这里用cnt1,cnt2来表示。


#include 
#include 
using namespace std;
const int N=1010;
int f[N][N];
string s1, s2;//要输入的两个序列
string str1[N], str2[N];//记录两个序列的所有子序列
int cnt1, cnt2;//相当于每个子序列的下标
int main()
{
    cin >> s1 >> s2;
    int d1 = s1.length(), d2 = s2.length();
    for (int i = 0; i < d1;)
    {
        cnt1++;
        if (s1[i] >= 'A' && s1[i] <= 'Z')//子序列首字母大写,后几位全小写
        {
            str1[cnt1] += s1[i++];
            while (s1[i] >= 'a' && s1[i] <= 'z')
            {
                str1[cnt1] += s1[i++];
            }  
        }
    }
    for (int i = 0; i < d2;)
    {
        cnt2++;
        if (s2[i] >= 'A' && s2[i] <= 'Z')
        {
            str2[cnt2] += s2[i++];
            while (s2[i] >= 'a' && s2[i] <= 'z')
            {
                str2[cnt2] += s2[i++];
            }   
        }
    }
    for (int i = 1; i <= cnt1; i++)//遍历所有子序列
        for (int j = 1; j <= cnt2; j++)
        {
          f[i][j] = max(f[i][j - 1], f[i - 1][j]);
            if (str1[i] == str2[j]) f[i][j]=max(f[i][j], f[i - 1][j - 1] + 1);
           
        }
    cout << f[cnt1 ][cnt2 ] << endl;
    return 0;
}
5.包子凑数

 题解思路:这题一看就是完全背包问题的变种版,有几个物品,每个物品无限个,每个物品选任意个,能否凑到某个重量。


首先我们来了解一下什么是裴蜀定理:若a,b是整数,且gcd(a,b)=d,那么对于任意的整数x,y,ax+by都一定是d的倍数,特别地,一定存在整数x,y,使ax+by=d成立。


那么由裴蜀定理我们可知,若两个数x,y的gcd(x,y)为1,即 ax+by=1,ax+by一定是d的倍数,如果gcd不为一,那么就会存在数是x和y凑不出来的,

结论是如果所有的数的最大公约数不为1,就有不能凑出的数,并且小于10000,否则就有无限个(99和98是100内最大的互质的数,所以这个上界选择10000。


dp[i][j] 表示只取前i种笼子看看总和j是否能凑出来

#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 10010;
int f[N];
int a[110];
int gcd(int a, int b) {
	return b == 0 ? a : gcd(b, a % b);
}
int main() {
	int n;
    cin >> n;
	int d = 0;
	for (int i = 1; i <= n; ++i) {
		cin >> a[i];
		d = gcd(d, a[i]);
	}
	if (d != 1)cout << "INF" << endl;
	else {
		f[0] = 1;
		for (int i = 1; i <= n; ++i) {
			for (int j = a[i]; j <= 10000; ++j) {
				f[j]=max(f[j], f[j - a[i]]);//优化成1维
			}
		}
		int res = 0;
		for (int i = 0; i <= 10000; ++i)
			if (!f[i])res++;
		cout << res << endl;
	}
	return 0;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/562304.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-01
下一篇 2022-04-01

发表评论

登录后才能评论

评论列表(0条)