SMU Summer 2024 Contest Round 6

Many Formulas

给了你一个字符串,你可以在任意两个字符间插入加号,而且也可以插入任意个,问你这些所有可能的算式的结果加和是多少。

那我们可以来看一下,这个字符串长度很小,我们可以举例出所有可能产生的数,记录下这个数的大小,这个数产生的位置,这个数的数位长度。对于每一个数字,我们都可以算出它可能被加和几次。每一个数面临的情况如下:——数——,枚举一下这个数之前——的位数为1,2,3,4的情况,会发现当为1时,无法插入,为0次,2时为不插和插入1个,为2次,3时为4次,4时为8次,可以看出这就是2的(n-1)次方个,后面——位数的算法与前面一致。两者在和本数去相乘。我们就可以算了。
 

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>

void solve() {
	string s;
	cin>>s;
	int n=s.size();
	int sum=0;
	vector<pair<int,pair<int,int>>>a;
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			int z=0;
			for(int k=j;k<=j+i and j+i<n;k++){
				z=z*10+(s[k]-'0');
			}
			if(z!=0){
				a.push_back({z,{i+1,j}});
			}
		}
	}
	for(int i=0;i<a.size();i++){
		int n1=a[i].second.second;
		int n2=n-a[i].second.first-a[i].second.second;
		if(n1>0){
			n1--;
		}if(n2>0){
			n2--;
		}
		sum+=a[i].first*pow(2,n1)*pow(2,n2);
	}
	cout<<sum<<endl;
	
}

signed main() {
	ios::sync_with_stdio ( false );
	cin.tie ( nullptr );
	cout.tie ( nullptr );
	int oyyo = 1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

Wall

😭。

弗洛伊德(Floyd)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
int a[205][205];
int c[15][15];
void solve() {
	int n,m;
	cin>>n>>m;
	int k=1;
	for(int i=0;i<10;i++){
		for(int j=0;j<10;j++){
			cin>>c[i][j];
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
			if(a[i][j]!=1 and a[i][j]!=-1){
				k=0;
			}
		}
	}
	if(k==1){
		cout<<0<<endl;return;
	}
	
	for(int i=0;i<=9;i++){
		for(int j=0;j<=9;j++){
			for(int z=0;z<=9;z++){
				c[j][z]=min(c[j][i]+c[i][z],c[j][z]);
			}
		}
	}
	int sum=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i][j]!=1 and a[i][j]!=-1){
				sum+=c[a[i][j]][1];
			}
		}
	}
	cout<<sum<<endl;
	
}

signed main() {
	ios::sync_with_stdio ( false );
	cin.tie ( nullptr );
	cout.tie ( nullptr );
	int oyyo = 1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

Tak and Cards

给你一个序列,再给你一个数,让你算出这个序列里有多少个子序列的平均值为A。

我们利用动态规划求解,利用dp[i][j][k]来记录前i个数里选j个数总和为k的方案数。

因为最大的运算结果是k=50*50=2500,而j和i都可以取50所以最大为50^{4}如果我们#define int long long 的话会爆掉,long long无法存下,所以我们考虑滚动数组。我们发现每一层i都是由上一层i-1来决定的,因此我们只需要保存两个状态就好了。状态的转移是,对于一个新的循环。他可以继承上一轮选了j个数总和为z的方案数,如果他当前表示的“和”(z)大于当前要判断的数a[i]的话,那么他就可以在继承的基础上,再加上上一轮选了j-1个数,总和为z-a[i]的结果。最后判断在所有n个数里选i(1<=i<=n)个数,平均数是A的结果。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
const int N=51;

int dp[2][N][N*N];
int a[55];
int sum[55];
void solve() {
	
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum[i]=sum[i-1]+a[i];
	}
	
	int now=1;
	dp[1][0][0]=dp[0][0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			for(int z=0;z<=sum[i];z++){
				dp[now][j][z]=dp[now^1][j][z];
				if(z>=a[i]){
					dp[now][j][z]+=dp[now^1][j-1][z-a[i]];
				}
			}
		}
		now^=1;
	}
	int sum=0;
	for(int i=1;i<=n;i++){
		sum+=dp[now^1][i][i*m];
	}
	cout<<sum<<endl;
}

signed main() {
	ios::sync_with_stdio ( false );
	cin.tie ( nullptr );
	cout.tie ( nullptr );
	int oyyo = 1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

Nearest Excluded Points

题目给了你n个红点,让你去找每个红点周围的点,满足这个点在红点队列里,并且距离当前红点的曼哈顿距离最小。

红点一共有两种状况,①上下左右不全是红点。②上下左右全是红点。

对于第一种情况。我们可以直接去找这个点的上下左右。找到了就是最短。

对于第二种情况,因为他是被红点包围的,我们就从“边缘”上的红点(已经找到最短曼哈顿距离点的红点)出发,向内去缩小未知点范围。(如果这个点A周围有一个已经找到最近曼哈顿点C的红点B,那么这个曼哈顿点C,同样是新红点A的最近曼哈顿点)

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>


int dx[]={0,0,-1,1};
int dy[]={-1,1,0,0};
    
void solve() {
	
	int n;
	cin>>n;
	vector<pair<int,int>>a(n);
	for(int i=0;i<n;i++){
		cin>>a[i].first>>a[i].second;//每个红点的信息
	}
	
	set<pair<int,int>>st(a.begin(),a.end());//筛选红点。
	map<pair<int,int>,pair<int,int>>u;
	queue<pair<int,int>>q;
	
	for(auto c:a){//对于一个红点遍历他的周围,用来判断一个点周围全是红点的状况。
		for(int i=0;i<4;i++){
			int nx=c.first+dx[i],ny=c.second+dy[i];
			if(st.count({nx,ny})){
				continue;//如果是红点。跳过。
			}
			u[{c.first,c.second}]={nx,ny};
			//只要周围有一个不是红点,那么这个点到红点的距离就是1,这个就是最近的点。
			q.push({c.first,c.second});//现在可以把这个点塞到队列中,用来解决一个点周围全是红点的状况。
			break;//这个点已经找到离他最近的点了,可以break,判断下一个点了。
		}
	}
	//现在开始找一个红点周围全是红点包围的情况。
	while(!q.empty()){//遍历所有的红点。
		int x=q.front().first,y=q.front().second;
		q.pop();
		for(int i=0;i<4;i++){
			int nx=x+dx[i],ny=y+dy[i];
			if(!st.count({nx,ny}) or u.count({nx,ny})){
				continue;//遍历这个红点的周围。如果它不是被标记的红点,或这个红点已经被判断过(说明他不是周围全是红点的红点。我们已经找过了)
			}
			u[{nx,ny}]=u[{x,y}];//然后这个点的最近点就是他周围红点的最近点。这样距离是最小。
			q.push({nx,ny});//现在这个新点也被找到了,可以加到队列里,用来去找更加内部的点了。
		}
	}
	
	for(auto& c:a){//输出
		auto it=u[{c.first,c.second}];
		cout<<it.first<<" "<<it.second<<endl;
	}
}   
    
signed main() {
	ios::sync_with_stdio ( false );
	cin.tie ( nullptr );
	cout.tie ( nullptr );
	int oyyo = 1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值