2021年填空

2021年省A第一场

A、卡片

0到9的卡片各2021张,够从1拼到哪个数字?
3181:用数组存储个数+遍历

int main(){
	int have[10],now=1,x;
	for (int i=0;i<10;i++) have[i]=2021;
	while (1){
		x=now;
		while (x){//能否拼成 
			if (have[x%10])have[x%10]-=1;
			else break;
			x/=10;
		}
		if (x) break;
		else now+=1;
	}
	cout<<now-1; //最后一个没拼成 
	return 0;
}

B、直线

在这里插入图片描述
40257:斜率为0和斜率不存在的情况共20+21=41条。对正常斜率的点计算k 和 b,因为doubl有精度损失千万不能用k算b和用b算k,都直接根据联立等式算!然后用map去重记录个数即可。

#define maxn 1000
#define maxx 20
#define maxy 21
using namespace std;
struct node{int x,y;};//存储点
map<double,map<double,int> > k; //储存斜率和截距
int main(){
	int c=0,cnt=0,t;
	node dot[maxn];
	for (int i=0;i<maxy;i++){
		for (int j=0;j<maxx;j++) dot[c++]={j,i};//记录点
	}

	for (int i=0;i<c;i++){//较小点
		for (int j=i+1;j<c;j++){
			if (dot[i].x!=dot[j].x && dot[i].y!=dot[j].y){//有斜率
				double x = double(dot[j].y-dot[i].y)/double(dot[j].x-dot[i].x);
				double b = double(dot[j].x*dot[i].y-dot[i].x*dot[j].y)/double(dot[j].x-dot[i].x);
				if (k[x].find(b)==k[x].end()) cnt+=1;
				k[x][b]=1;
			}
		}
	}
	cout<<cnt+maxx+maxy;
	return 0;
}

C、货物摆放

在这里插入图片描述
2430:使得三个因子非降序,求其全排列之和

typedef long long ll;
int main(){
	ll in = 2021041820210418,t,cnt=0;
	//非降序三个因子 
	for (ll i=1;i<ll(sqrt(in))+1;i++){
		if (in%i==0){
			t = in/i;
			for (ll j=i;j<ll(sqrt(t))+1;j++){ 
				if (t%j==0){
					if (i==j){//两个数字一样 
						if (i==t/j) cnt+=1;//三个数字一样 
						else cnt+=3;
					}
					else if (j==t/j) cnt+=3;//两个数字一样 
					else cnt+=6;//三个数字不同 
				}
			}
		}
	}
	cout<<cnt;
	return 0;
}

D、路径

在这里插入图片描述
10266837:动态规划令dp存储长度,dp[1]=0,dp[x]=min(dp[可到达x的i]+i x之间的花费)

int gcd(int x,int y){return y?gcd(y,x%y):x;};
int main(){
	int dp[2022],maxi;
	dp[1]=0;
	for (int i=2;i<2022;i++){
		maxi = 99999999;
		for (int j=max(1,i-21);j<i;j++){
			if (dp[j]+i*j/gcd(i,j)<maxi) maxi=dp[j]+i*j/gcd(i,j); //找最短路径 
		}
		dp[i]=maxi;
	}
	cout<<dp[2021];
	return 0;
}

E、回路计数

在这里插入图片描述
881012367360:一开始想的是图+dfs,用cost[i][j]记录路径,2 ^ 21复杂度根本跑不完TAT。所以学习了状压dp,用21位二进制串表示第k栋有没有走过,以后就是哈密顿回路板子题:换成0到20号楼容易理解和计算。

typedef long long ll;
ll cost[25][25],dp[1<<21][25],res=0;
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;};
int main(){
	//路径初始化 
	for (int i=1;i<22;i++){
		for (int j=1;j<i;j++){
			if (gcd(i,j)==1) cost[i-1][j-1]=cost[j-1][i-1]=1;//互质
			else cost[i-1][j-1]=cost[j-1][i-1]=0; 
		}
		cost[i-1][i-1]=0;
	}
	//状态压缩dp,dp[i][j]表示从i到j的方案数 
	dp[1][0]=1; 
	for (int i=1;i<(1<<21);i++){
		for (int j=0;j<21;j++){
			if (i>>j&1){//当前状态走过j 
				for (int k=0;k<21;k++){
					if (!(i>>k&1) && cost[j][k])//未走过k,j k有路 
						dp[i+(1<<k)][k]+=dp[i][j];
				}
			}
		}
	} 
	//将所有可回到1的回路求和
	for (int i=1;i<22;i++) res+=dp[(1<<21)-1][i];
	cout<<res;
	return 0;
}

2021年省A第二场

A、双乘积

在这里插入图片描述
59375:边遍历边求模

int main(){
	int res = 1 , mod=100000;
	for (int i=1;i<2022;i+=2) res = (res*i)%mod;
	cout<<res;
	return 0;
}

B、格点

在这里插入图片描述
15698:边遍历边判断

int main(){
	int cnt=0;
	for (int i=1;i<2022;i++){
		for (int j=1;j<2022;j++){
			if (i*j<=2021) cnt+=1;
		}
	}
	cout<<cnt;
	return 0;
}

C、整数分解

在这里插入图片描述
691677274345:乘法分解和加法分解我都形成非递减序列,分情况讨论暴力。但加法分解可套用隔板法模型,共2020个位置放置4个板C(20,4),所以小心long long溢出边乘边除几行代码就搞定 。。。

typedef long long ll;
int main(){
	ll cnt=0;
	for (int i=1;i<2021;i++){
		for (int j=i;j<2021-i;j++){
			for (int k=j;k<2021-i-j;k++){
				for (int p=k;p<2021-i-j-k;p++){
					int q = 2021-i-j-k-p;
					if (q>=p){//非递减5个数序列 
						if (i==j){
							if (j==k){
								if (k==p){
									if (p==q) cnt+=1; //C55 五个数相同
									else cnt+=5;//C51四个数相同 
								}
								else{
									if (p==q) cnt+=10; //C52 3个数相同,2个数相同
									else cnt+=20;  //A52 3个数相同,2个数不同
								}
							}
							else{
								if (k==p){
									if (p==q) cnt+=10; //C52 2个数相同,3个数相同
									else cnt+=30;//C51*C42 2个数相同,2个数相同 
								}
								else{//2个数相同
									if (p==q) cnt+=30; //C51*C42 2个数相同
									else cnt+=60;  //A53 3个数不同
								}								
							}
						}
						else{
							if (j==k){
								if (k==p){
									if (p==q) cnt+=5; //C51 4个数相同
									else cnt+=20;//A52 3个数相同,2个数不同
								}
								else{
									if (p==q) cnt+=30;//C51*C42 2个数相同,2个数相同 
									else cnt+=60;  //A53 3个数不同
								}
							}
							else{
								if (k==p){
									if (p==q) cnt+=20;  //A52 3个数相同,2个数不同
									else cnt+=60;  //A53 3个数不同
								}
								else{
									if (p==q) cnt+=60;  //A53 3个数不同
									else cnt+=120;  //A55 5个数不同
								}								
							}
						}
					}
					else break;//后面更不可能 
				}
			}
		}
	}
	cout<<cnt;
	return 0;
}

隔板法,加法分解yyds

typedef long long ll;
int main(){
	ll cnt=1;
	for (ll i=1;i<5;i++){
		cnt = (cnt*(2021-i))/i;//及时除以防止溢出 
	}
	cout<<cnt;
	return 0;
}

D、城邦

在这里插入图片描述
4046:node结构体存储无向图每条边,按花费递增后,最小生成树の并查集算法将答案找出来。

#include <iostream>
#include <algorithm>
#define maxn 2022
using namespace std;

struct node{int x,y,cost;};
node e[2041220];
int head[maxn],c=0,r=0;

bool cmp(node a,node b){
	if (a.cost==b.cost) return (a.x<b.x);
	return (a.cost<b.cost);
}
int sum(int x,int y){
	int res=0;
	int xa=x%10,ya=y%10;
	int xb=(x/10)%10,yb=(y/10)%10;
	int xc=(x/100)%10,yc=(y/100)%10;
	int xd=(x/1000)%10,yd=(y/1000)%10;
	if (xa!=ya) res+=xa+ya;
	if (xb!=yb) res+=xb+yb;
	if (xc!=yc) res+=xc+yc;
	if (xd!=yd) res+=xd+yd;
	return res;
}
int f(int x){
	if (head[x]==x) return x;
	return head[x]=f(head[x]);
}
void together(int x,int y){
	int a=f(x),b=f(y);
	if (a!=b) head[b]=a;
}
int main(){
	//图初始化 
	for (int i=1;i<maxn;i++){
		for (int j=i+1;j<maxn;j++) e[c++]={i,j,sum(i,j)};	
		head[i]=i;
	}
	sort(e,e+c,cmp);//根据长度排序 
	for (int i=0;i<c;i++){
		if (f(e[i].x)!=f(e[i].y)){//最小生成树 
			together(e[i].x,e[i].y);
			r+=e[i].cost;
		}
	}
	cout<<r;
	return 0;
}

E、游戏

在这里插入图片描述
1352184317599:用动态规划做的但存不下长度为20210509的dp啊TAT
大佬用递归+循环找因子,跑十几分钟出来了。。。真考试就先放弃E题吧,一般F更简单TAT

typedef long long ll;
ll f[20210510];
ll dfs(int n){
	if(f[n] != -1) return f[n];
	if(n == 1) return 1;
	f[n] = 0;
	for (int i=1;i<=n/i;i++)
		if(n%i==0){//是因子 
			f[n]+=dfs(i);
			if(n/i!=i&&n/i<n) f[n]+=dfs(n/i);//去掉相同因子和自身的情况 
		}
	return f[n];
}
int main(){
	ll ans = 0;
	memset(f, -1, sizeof f);
	for (int i=1;i<=20210509;i++) ans+=dfs(i);//累加 
	cout<<ans<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值