蓝桥杯刷题记录:2021第十二届C++省赛真题(待更新)

T1:砝码称重

原题链接:https://www.dotcpp.com/oj/problem2604.html

DP代码:(100分)

#include
#include
#include
using namespace std;
const int N=110,M=2e5+10;
int sum,n,w[N];
bool f[N][M];

int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		cin>>w[i];
		sum+=w[i];
	}
	f[0][0]=true;
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=sum;j++)
		{
			f[i][j]=f[i-1][j] || f[i-1][j+w[i]] || f[i-1][abs(j-w[i])];
		}
	}
	int ans=0;
	for(int i=1;i<=sum;i++)
		if(f[n][i])
			ans++;
	cout<

DFS代码:(100分)

#include
#include
#include
using namespace std;
int n,res;
int w[1000000];
bool st[1000000];
bool memo[110][200010];//记忆化搜索需要 
void dfs(int k,int sum)//考虑k个砝码重量凑出sum,中间有跳过不选的环节 
{//不一定是全部都选上 
	if(memo[k][sum])//如果sum被凑出过直接返回bool判断值 
		return; 
	memo[k][sum]=true;
	st[sum]=true;
	if(k>n)//全部选择完了
	{
		return;
	}
	else//考虑全部情况,考虑过就行 
	{
		dfs(k+1,abs(sum-w[k]));//放右边 
		dfs(k+1,sum);//不选 
		dfs(k+1,sum+w[k]);//放左边 
	}
}
int main()
{
	cin>>n;
	int ans=0;
	for(int i=1;i<=n;i++)
		cin>>w[i];
	dfs(1,0);
	for(int i=1;i<=200010;i++)
		if(st[i])
			ans++;
	cout<

T2:异或序列:

题解:

    初始时A和B都为0, 由异或的性质最终 A⨁B=X1⨁X2⨁Xi…
(1)如果所有XX异或的结果为0,那么说明最终的A 和 B 是相同的,直接输出平局00。
(2)如果要使得最终结果最大,那么肯定优先选最高位的1,我们记录每一位上1出现的次数
由于异或中:
与 1 异或是取反,与 0 异或不变,

也就是把所有数的每一位的1统计个数,统计结果为所有数在所有位上出现的个数。
当某一位的num[i]为偶数,则游戏结果的这一位一定相等(取反偶数次还是原数),直接看下一位出现的次数

如果num[i]的个数为1,则一定是先手赢(抢了1之后,就没有1了|只有A最高位变成了1)(可以理解为没有1让他取反了
那么当num[i]为大于1的奇数, 0的个数为偶数,则先手赢——
先手抢1,然后之后都和对手取一样
当num[i]为大于1的奇数, 0的个数为奇数,则后手赢——先手抢1,0都反他

时间超限83%:

#include
#include 
#include
#include
using namespace std;
const int N=22;
int num[N];//总的每位1出现个数 
int k,sum,n;
void jilu(int n)
{
	int cnt=1;
	while(n)//位运算 
	{
		if(n&1)//判断这一位是不是1 
			num[cnt]++;
		cnt++;
		n>>=1;//整体左移,把最后一位搞掉,反正后面也用不到了 
	}
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		memset(num,0,sizeof num);
		sum=0;
		cin>>k;
		for(int i=0;i>s;
			jilu(s);//处理下num[] 
			sum=sum^s;//反正终点都是sum=x[1]^x[2]^……^x[n] 
		}
		if(!sum)//如果结果不是1的话直接平局 
			puts("0"); 
		else
		{
			for(int i=20;i>=1;i--)//最大数不会超2^20 
			{
				if(num[i]==1)//只有一个1先手抢就行 
				{
					puts("1");
					break;
				}
				else if(num[i]&1)//判断1个数是奇数 
				{
					if(k%2==0)//0奇数后手赢 
					{
						puts("-1");
						break;
					} 
					else
					{
						puts("1");
						break;
					}
				} 
			}
		} 
	} 
	return 0;
}

T3:左孩子右兄弟:

vector建树:

//vector建树法 
#include
#include
#include
#include
#define N 100010
using namespace std;
vector g[N];//存子节点 
int n,x; 
int dfs(int u)
{
	int ans=0;
	int cnt=g[u].size();//记录根节点的孩子数,最后加上就行 
	for(int i=0;i>n;
	for(int i=2;i<=n;i++)
	{
		cin>>x;//输入他的父节点 
		g[x].push_back(i);//vector存父节点下属的子节点是哪一个 
	} 
	int sum=dfs(1);
	cout<>n;
	for(int i=1;i>a[i];
		maxx=max(maxx,a[i]);
	}
	a[1]=1;
	sum=1;
	while(a[sum]!=maxx)
	{
		sum++;
	}
	cout<

邻接表建树法:

#include
#include
#include 
#include
using namespace std;
const int N=1e5+10;
int a[N],ne[N],e[N],h[N],idx;
int num[N],f[N];
void add(int a,int b)//邻接表建树 
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
int dfs(int u,int fa)
{
	for(int i=h[u];!i;i=ne[i])
	{
		int j=e[i];
		if(j!=fa)//保证递归向下 
		{
			dfs(j,u);
			f[u]=max(f[u],f[j]+num[u]); 
		}
	}
} 
int main()
{
	int n;
	cin>>n;
	memset(h,-1,sizeof h);
	for(int i=2;i<=n;i++)
	{
		int x;
		cin>>x;
		add(x,i);
		num[x]++;//子节点个数 
	}
	dfs(1,-1);
	cout<

T4杨辉三角形:

思路图:

蓝桥杯刷题记录:2021第十二届C++省赛真题(待更新)_第1张图片

 代码详解:

#include
#include
#include
using namespace std;
typedef long long LL;
int n;

LL c(int a,int b)
{
	LL res=1;
	for(int i=a,j=1;j<=b;j++,i--)
	{
		res=res*i/j;
		if(res>n)//大于n的话不用管 
			return res;
	}
	return res; 
}
bool check(int k) 
{
	int l=2*k,r=max(n,l);//C(2k,k)-->C(n,k) 这里取n的原因我查到的就是以n为底的组合数必然比n大,但是可能会爆呀,搞不懂 
	//里取n的原因我查到的就是以n为底的组合数必然比n大
	//反正在后面取组合数的函数里大于后会被直接返回不用管的 
	
	while(l>1; 
		if(c(mid,k)>=n)
			r=mid;//右边界取 
		else
			l=mid+1;
	}
	if(c(r,k)!=n)
		return false;
	cout<<1ll*(r+1)*r/2+k+1<>n;
	for(int k=16;;k--)//最大斜行数量不会超过16行 C(32,16)>1e9 
	{
		if(check(k))//找到当前斜行存在值就退出 
			break; 
	}
	return 0;
}

T5:最少砝码:

#include 
#include 
using namespace std;
int main() {
    int k;
    cin >> k;
    cout << ceil(log(2*k+1)/log(3)) << endl;
}

T6:特殊年份(简单题)

#include
#include
#include
#include
using namespace std;
 
int n,m,k;
int a,b,c,d;
char f[5];
int main()
{
	int cnt=0;
	for(int i=1;i<=5;i++)
	{
		for(int j=1;j<=4;j++)
		{
			cin>>f[j];
			if(j==1)
				a=f[j]-'0';
			if(j==2)
				b=f[j]-'0';
			if(j==3)
				c=f[j]-'0';
			if(j==4)
				d=f[j]-'0';
		}
		if(a==c && d==b+1)
			cnt++;
	}
	cout<

T7:小平方(简单题)

#include
#include
#include
#include
using namespace std;
int n,k;
double m;
int cnt=0;
int main()
{
	cin>>n;
	m=n/2.0;
	for(int i=1;i

T8:完全平方数(简单题)

#include
#include
#include
#include
typedef long long ll;
#define N 1000010
using namespace std;
ll n,m;
int main()
{
	cin>>n;
	ll res=1;
	for(ll i=2;i*i<=n;i++)//找质因子
	{
		if(n%i==0)//看他的这个质因子有几个 
		{
			int s=0;
			while(n%i==0)
			{
				s++;
				n/=i;
			} 
			if(s%2)//如果是奇数答案就要乘上他成为一个偶数 
				res*=i;
		}
	} 
	if(n>1)//还剩下单个的,凑个双 
		res*=n; 
	cout<

T9:负载均衡(优先队列模拟)

感谢Mangata大佬的博客指点~~~

#include
#include
#include
#include
using namespace std;
typedef pair PII;
#define ll long long
#define N 200010
int n,m,qq,a,b,c,d,v[N];
priority_queue,greater >q[N]; 
int main()//用优先队列原因:我们需要找到最先结束的任务时间以及精力 
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)	cin>>v[i];
	for(int i=0;i>a>>b>>c>>d;
		while(q[b].size())
		{
			int ed=q[b].top().first;//最开始结束的任务时间 
			int k=q[b].top().second;//当前最先结束的任务精力
			if(ed>a)//如果现在的最先结束任务的时间已经超出那么后面任务就不用考虑了 
				break;
			v[b]=v[b]+k;//任务结束后就还原精力,给下一步使用
			q[b].pop();//把目前结束的任务弹出 
		} 
		if(v[b]

T10:填空题卡片:

蓝桥杯刷题记录:2021第十二届C++省赛真题(待更新)_第2张图片

 

#include
using namespace std;

int n,m,k;
int a[10]; 
int main()
{
	for(int i=0;i<=9;i++)
		a[i]=2021;
	int n=1;
	while(1)
	{
		int s=n;
		while(s){
			if(a[s%10])
				a[s%10]--;
			else
				break;
			s/=10;
		}
		if(s)
			break;
		else
			n++;
	}
	cout<

你可能感兴趣的:(acm刷题,蓝桥杯,c++,算法,数据结构)