csp-202209

题目一:如此编码【100分】

比较简单的题,根据题意计算一遍就行
一定要关注csp题目中的提示,这个是很有用的
AC代码:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int N=25;
typedef long long LL;
int n;
LL m;
int a[N];
LL c[N];
int b[N];
int main() {

	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	c[0]=1;
	c[1]=a[1];
	for(int i=2;i<=n;i++)
	{
		c[i]=c[i-1]*a[i];
	}
	for(int i=1;i<=n;i++)
	{
		LL t=m%c[i];
		LL sum=0;
		for(int j=0;j<i-1;j++)
		{
			sum+=c[j]*b[j+1];
		}
		t-=sum;
		b[i]=t/c[i-1];
		cout<<b[i]<<" ";
	}
	return 0;
}

题目二:何以包邮?【100分】

比赛的时候,就感觉跟0/1背包很像,就一直朝着那个方向去做,但是我dp太差了,当时的环境下怎么都想不出来,最后想着算了,枚举吧,得70分也挺好的,就用回溯简单枚举了一下
回溯枚举,,得到的是一个二叉树,时间复杂度为O(2^n)
当n<=15时,为O(2^15)=32768 ,1s内能过
当n<=30是,为O(2^30)=1073741824>1e8 ,肯定超时
70分回溯枚举代码:

#include<bits/stdc++.h>
using namespace std;
const int N=35;
int INF=0x3f3f3f3f;
int a[N],n,x,ans=INF,now;
void back(int i)
{
	if(i>n) 
	{
		if(now<x) return ;
		if(now<ans) ans=now;
		return ;
	}
	//选
	now+=a[i]; back(i+1);
	//不选 
	now-=a[i];back(i+1);
}
int main() {
	cin>>n>>x;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	back(1);
	cout<<ans;
	return 0;
}

但其实这个回溯是可以优化来混点分的,加点剪枝什么的
然后再看dp背包方法,寻找大于等于包邮条件x的最小花费,其实发过来看,就是用总买的书的价格减去满足包邮条件x得到v,得到不超过v的最大花费,最后再用总价格减去这个不超过v的最大花费,就得到了结果,后者其实就是规范的0/1背包问题
AC代码:

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int N=35;
const int M=1000005;
int a[N];
int n,x,sum=0,dp[N][M];
int main() {

	cin>>n>>x;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];sum+=a[i];
	}
	int v=sum-x;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=v;j++)
		{
			if(j>=a[i]) dp[i][j]=max(dp[i-1][j],dp[i-1][j-a[i]]+a[i]);
			else dp[i][j]=dp[i-1][j];
		}
	}
	cout<<sum-dp[n][v];
	return 0;
}

再利用一下滚动数组进行空间优化:

#include<iostream>
using namespace std;
const int N=35;
const int M=1000005;
int a[N];
int n,x,sum=0,dp[M];
int main() {

	cin>>n>>x;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];sum+=a[i];
	}
	int v=sum-x;
	for(int i=1;i<=n;i++)
	{
		for(int j=v;j>=a[i];j--)
		{
			dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
		}
	}
	cout<<sum-dp[v];
	return 0;
}

在这里插入图片描述

题目三:防疫大数据【100分】

  1. 按照以前的csp认证惯例,第三题是大模拟题,静下心来,慢慢做,变量什么的直接用题目里的变量表示就行了,不用再自己编变量;
  2. 大致思路就是,先把所有的用户漫游记录和风险地区记录存起来,最后在每天遍历近七日的游客记录,再根据题目的三个要去进行筛选遍历即可;
  3. 注意一个问题:题目中的日期可以是负数,从最后30分能明显看出来,dij的范围为[-1e5,i],因此用普通的一维或者二维数组就会出错,此时用map是最好的,map支持[]获取数值,并且[]内允许索引为负数(几乎任何类型)

AC代码:
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef struct Node
{
	int d;
	int u;
	int r;
}UserNode,*User; 
map<int,vector<User>>manyou;  //第i天的漫游记录 
int n,ri,mi;
set<int>ans;   //有序的输出用户列表 
map<int,map<int,int>>fengxian;  //每个风险地区对应的风险日期 
int main() { 	

	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>ri>>mi;
		for(int j=0;j<ri;j++) 
		{
			int t;cin>>t;
			for(int k=i;k<i+7;k++) fengxian[t][k]=1;
		}
		for(int j=0;j<mi;j++)
		{
			User user=new UserNode;
			cin>>user->d>>user->u>>user->r;
			manyou[i].push_back(user);
		}
		for(int k=i;k>i-7;k--)  //遍历近7日的漫游数据 
		{
			int len=manyou[k].size();
			for(int j=0;j<len;j++)
			{
				User user=manyou[k][j];
				if((user->d>i-7&&user->d<=i)&&fengxian[user->r][user->d]) //到访的那一天处于风险状态 
				{
					//该地区从到访日到目前持续处于风险状态
					bool f=true;
					for(int h=user->d;h<=i;h++)
					{
						if(!fengxian[user->r][h])  
						f=false;
					} 
					if(f) ans.insert(user->u);
				} 
			}
		}
		cout<<i<<" ";
		for(set<int>::iterator it=ans.begin();it!=ans.end();it++)
		{
			cout<<*it<<" ";
		}
		cout<<endl;
		ans.clear();
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值