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、城邦

在这里插入图片描述
50468:2021个城市要连2020座桥,除了两头的都要加两次,所以找出耗费最多及第二多的点(使用数字1 7 8 9的)只加1次即可。

#define M 9999999
using namespace std;
typedef long long ll;
int sum(int x){
	int res=0;
	map<int,int> m;
	for (int i=0;i<4;i++){
		if (m.find(x%10)==m.end()){
			m[x%10]=1;
			res+=x%10;
		}
		x/=10;
	}
	return res;
}
int main(){
	int max1=0,max2=0,r=0,t;
	for (int i=1;i<2022;i++){
		t = sum(i);
		if (t>max1) max1=t;//最大 
		else if (t>max2) max2=t;//第二大 
		r += t;
	}
	cout<<r*2-max1-max2; //最费的当两头 
	return 0;
}

E、游戏

在这里插入图片描述
用动态规划做的但存不下长度为20210509的dp啊TAT, 还是并查集?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值