递推+模拟---想好如何存储?

递推+模拟

    • 输入输出问题
    • CCF-CSP考试历年真题题型分类
      • 分组输入——可能有多组测试数据,对于每组数据
    • 递推---从前面已知态--->后续未知态
      • AcWing 3777. 砖块
      • AcWing 1208. 翻硬币
      • AcWing 1211. 蚂蚁感冒
      • AcWing 3433. 吃糖果
      • AcWing 821. 跳台阶
    • 模拟
      • 202212-2-csp-训练计划
      • 202206-2-csp-寻宝!大冒险!---稀疏矩阵---数学坐标系
      • 202112-2-csp-序列查询新解---数学问题
      • 202009-2-csp-风险人群筛查
      • 201912-2-csp-回收站选址
      • 201909-2-csp-小明种苹果(续)
      • 201812-2-csp-小明放学
      • 201809-2 -csp-买菜
      • 201703-2-csp-学生排队
      • 201612-2 -csp-工资计算
      • 201609-3-csp-炉石传说
      • 201609-2-csp-火车购票
      • 201604-2-csp-俄罗斯方块(利用下一个时刻判断+补充最后一层满格)
      • 201512-2-csp消除类游戏
      • 201312-3-csp-最大的矩形
      • 201412-3-csp-集合竞价
      • 201403-2-csp-窗口
      • AcWing 3426. 糖果分享游戏
    • 矩阵扫描
      • AcWing 756. 蛇形矩阵
      • 201412-2-csp-Z字形扫描
    • 日期问题
      • 日期问题常用模板
      • 计数月,日或分钟等等
      • AcWing 3607. 打印日期
      • 201509-2csp日期计算---上一个题的按月模拟版
      • AcWing 3573. 日期累加
      • AcWing 1341. 十三号星期五
      • 201503-3csp节日
    • 结构体排序
      • AcWing 3375. 成绩排序
      • AcWing 429. 奖学金
      • 201803-2-csp-碰撞的小球
      • 201709-2-csp公共钥匙盒---还钥匙/取钥匙分为两种操作---拆点法
      • 201503-2-csp-数字排序
    • 字符串
      • 字符串常用操作---字符串本质是字符数组
      • AcWing 3439. 首字母大写
      • AcWing 3504. 字符串转换整数
      • AcWing 3406. 日志排序
      • 201312-2-csp-ISBN号码
      • AcWing 1204.错误票据(stringstream读取)
      • 201403-3-命令行选项
      • AcWing1231.航班时间(时间模拟+时差处理+字符串处理)
      • 201409-3-csp-字符串匹配
      • 201604-3-csp-路径解析
      • 201509-3-csp-模板生成系统

输入输出问题

CCF-CSP考试历年真题题型分类

CCF-CSP考试历年真题题型分类

分组输入——可能有多组测试数据,对于每组数据

当你加上这个时,只要你不输入 ^Z(ctrl+z) , 条件为真,就会一直循环下去,只有你输入 ^Z,条件为假,终止循环。
BC100 直角三角形图案

#include
using namespace std; 
int main()
{
   
	int n = 0;
	while (cin>>n)//大家在分组输入时直接用起来呀!
	{
   
		for (int i = 0; i < n; i++)
		{
   		for (int a = 0; a <= i; a++)
				printf("* ");
				printf("\n");		           
		}
	}
	return 0;
}



递推—从前面已知态—>后续未知态

AcWing 3777. 砖块

AcWing 3777. 砖块

题目大意:求翻转相邻的两个砖块能否是所有颜色都相同!!

思路:递推!强调递推只是一种思路,没有模板!!!

砖块翻转2次以上都是重复的,因此只需要判断它翻转1次还是0次!!问题就简化成为判断此时的砖块需不需要翻转!!
我们假设所有砖块最后都能翻转成B,从1—n-1,进行比较判断第i个颜色是否与B相同,不同则翻转i与i+1个,依次判断完全后会发现1–n-1都翻转成为了B,此时第n个无法翻转,只需判断第n个颜色即可!

同理,假设最后都能翻转成W,如果两种假设都不能实现,则样例无法满足!!!

#include
using namespace std;
int n;
void update(char &c)//翻转第i个字符 
{
   
	if(c=='W')	c='B';
	else	c='W';
 } 
bool check(string s,char c)
{
   
	vector<int> v;//存储是---第i次操作 
	for(int i=0;i<n-1;i++)//存储在[0,n-1]----翻转[0,n-2] 
	{
   
		if(s[i]!=c)//如果不是想要的字符----就翻转 
		{
   
			update(s[i]);
			update(s[i+1]);
			v.push_back(i);//记录下翻转了第[i,i+1]个砖块 
		}
	}
	if(s[n-1]!=s[0])	return false;//---翻转过程结束后,若最后一个字符与其他字符不一致 
	cout<<v.size()<<endl;//翻转操作的次数 
	for(auto x:v) cout<<x+1<<" ";//+1的原因---下标的原因 
	if(v.size())	cout<<endl;//若是---没有翻转过---则比翻转过少一个换行 
	return true; 
}
int main()
{
   
	int T;
	cin>>T;
	while(T--)
	{
   
		cin>>n;
		string s;
		cin>>s;
		if(!check(s,'W')&&!check(s,'B'))//这段代码&&前面不满足后面就不再执行,因此方便了代码书写!
			cout<<-1<<endl; 
	}
	return 0;
 } 

AcWing 1208. 翻硬币

AcWing 1208. 翻硬币

递推+模拟---想好如何存储?_第1张图片
如果通过每次翻转两枚相邻硬币,能从状态一变为状态二,则两个状态之间必定有偶数个不同状态的硬币。

模拟法:

从最左侧开始遍历,如果该位置硬币状态与目标不同,就翻动该位置和该位置后面的两枚硬币。

因为题目说了有解,所以遍历到倒数第二枚的时候,所有硬币状态就与目标相同了。

这个方法也有点贪心的思路,每次追求当前位置状态与目标状态一致。我还是喜欢称它为模拟法。

#include
using namespace std;
string st,ed;
int ans;
void update(char &c)//翻转第i个字符 
{
   
	if(c=='o')	c='*';
	else	c='o';
}
int solve()
{
   
	for(int i=0;i<st.size()-1;i++)//遍历[0,n-1]的字符 
	{
   
		if(st[i]!=ed[i]) 
		{
   
			update(ed[i]);//同时翻转[i,i+1]两枚硬币 
			update(ed[i+1]);
			ans++;//返回的答案 
		}
	}
	return ans;
}
int main()
{
   
	cin>>st;
	cin>>ed;
	cout<<solve()<<endl;
	return 0;
 } 

AcWing 1211. 蚂蚁感冒

AcWing 1211. 蚂蚁感冒
AcWing 1211. 蚂蚁感冒—讲解


#include
using namespace std;
const int N=50+10;

int a[N];

int main()
{
   
	int n;
	cin>>n;
	for(int i=0;i<n;i++)	cin>>a[i];
	int l=0;//感冒蚂蚁的右边---向左走 
	int r=0;//感冒蚂蚁的左边---向右走 
	for(int i=1;i<n;i++)
	{
   
		if(abs(a[0])<abs(a[i]) && a[i]<0)
			l++;
		if(abs(a[0])>abs(a[i]) && a[i]>0)
			r++; 
	}
	if(a[0]>0)//当感冒蚂蚁---向右走 
	{
   
		if(l!=0)
			cout<<l+r+1<<endl;
		else		//特殊情况 
			cout<<1<<endl;
	}
	else//当感冒蚂蚁---向左走 
	{
   
		if(r!=0)
			cout<<l+r+1<<endl;
		else		//特殊情况 
			cout<<1<<endl;
	}
	return 0;
}

AcWing 3433. 吃糖果

AcWing 3433. 吃糖果

#include
using namespace std;

const int N = 22;
int dp[N];
int main()
{
   
    int n;
    cin >> n;
    dp[0]=dp[1]=1;
    for(int i=2;i<=n;i++)
        dp[i]=dp[i-1]+dp[i-2];
    cout<<dp[n]<<endl;
    return 0;
}

AcWing 821. 跳台阶

AcWing 821. 跳台阶

#include
using namespace std;

const int N = 22;
int dp[N];
int main()
{
   
    int n;
    cin >> n;
    dp[1]=1;
    dp[2]=2;
    for(int i=3;i<=n;i++)
        dp[i]=dp[i-1]+dp[i-2];
    cout<<dp[n]<<endl;
    return 0;
}

模拟

202212-2-csp-训练计划

递推+模拟---想好如何存储?_第2张图片

#include
using namespace std;
const int N=110;

int rely[N];//记录i的依赖----i依赖于rely[i] 
int t[N];//每个科目的训练需要时间 

int early[N];
int late[N];
 
 
int main()
{
   
	int n,m;
	
	cin>>n>>m;
	for(int i=1;i<=m;i++)
		cin>>rely[i];//存储i的依赖是rely[i] 
	for(int i=1;i<=m;i++)
		cin>>t[i];
		
		
	//正向计算---最早开始时间	
	for(int i=1;i<=m;i++)
	{
   	
		if(!rely[i])//如果不依赖别的科目=1 
			early[i]=1;
		else		//如果依赖别的科目=别的科目最早开始时间+别的科目的训练时间 
			early[i]=early[rely[i]]+t[rely[i]]; 
		cout<<early[i]<<" ";
	 }
	cout<<endl;
	
	
	
	//计算最晚开始时间---倒着计算 
	bool success=true;//标记---每一个最晚时间是否合法 
	for(int i=m;i>=1;i--)
	{
   
		late[i]=n-t[i]+1;//i不被后面的科目所依赖时
		
		for(int j=i;j<=m;j++)//找到后面的j---在依赖i 
		{
   
			if(rely[j]==i)//i被后面的i所依赖---可能有多个依赖于i的
				late[i]=min(late[i],late[j]-t[i]);//最晚时间要尽可能的早些 		
		 } 
		if(late[i]<1)//最晚时间不合法时 
			success=false; 
	 }
	 if(success)//当每一个科目都满足要求时
	 {
   
	 	for(int i=1;i<=m;i++)
	 		cout<<late[i]<<" ";
	  } 
	return 0;
}

202206-2-csp-寻宝!大冒险!—稀疏矩阵—数学坐标系

AcWing 4510. 寻宝!大冒险!

对应+匹配+不越界

用pair存储绿化图中非零坐标,二维数组存储藏宝图坐标
遍历pair,分别以pair中的点作为藏宝图左下角的点
 边缘判断:
 绿化图和藏宝图上1的数量必须对应,当两者个数相等时进行判断
对应+匹配+不越界

题目超时的原因在于存储大地图的稀疏矩阵太大,遍历比较耗时长。
本解法利用局部地图减少了遍历的范围。

#include
using namespace std;
const int N= 1e3+10,M=55;
typedef pair<int,int> PII;
#define x first
#define y second
int b[M][M];
PII tree[N];

int main()
{
   
	int n,L,S;//树的棵数、绿化图和藏宝图的大小 
	cin>>n>>L>>S;
	for(int i=0;i<n;i++) cin>>tree[i].x>>tree[i].y;
	
	int tc=0;//记录藏宝图上树的个数 
	for(int i=S;i>=0;i--)//---注意坐标系的读入 
		for(int j=0;j<=S;j++)
		{
   
			cin>>b[i][j];
			tc+=b[i][j]; 
		}
			
	int ans=0;//统计答案的个数 
	for(int i=0;i<n;i++)
	{
   
		int sx=tree[i].x;
		int sy=tree[i].y;
		if(sx+S>L||sy+S>L)//如果地图上越界 ---经典的错误,标准的零分 
			continue;
		int cnt=0;//记录地图相应区域上---树的个数 
		bool flag=true;//是否相匹配 
		for(int j=0;j<n;j++)
		{
   
			int x=tree[j].x;
			int y=tree[j].y;
			if(x>=sx && x<=sx+S && y>=sy && y<=sy+S)//在区域内 
				if(!b[0+x-sx][0+y-sy])//地图上是树的位置---藏宝图上不是树时 
				{
   
					flag=false;//直接不匹配---返回 
					break;//不需要再判断下去了 
				}
				else
					cnt++;
		 } 
		 if(cnt==tc && flag)//个数相同---并且---匹配成功 
			ans++;
	}
	cout<<ans<<endl;
	return 0;
 } 

202112-2-csp-序列查询新解—数学问题

AcWing 4281. 序列查询新解

递推+模拟---想好如何存储?_第3张图片

递推+模拟---想好如何存储?_第4张图片

#include
using namespace std;
const int N=1e5+10;
typedef long long LL;
int n,m;
int a[N];
LL R;
LL get(int l,int r)  // 求g[l] + g[l + 1] + ... + g[r]
{
   
    if (l/R==r/R)//如果仅有一小段时 
		return (LL)(r-l+1)*(l/R);
		
    //g(x)有多段时 
    int a=l/R+1,b=r/R-1;
    LL res=(a+b)*(LL)(b-a+1)/2*R;  // 中间部分
    res+=(a-1)*(LL)(a*R-l);  // 左边界
    res+=(b+1)*(LL)(r-(b*R+R)+1);  // 右边界
    return res;
}

int main()
{
   
    cin>>n>>m;
    for (int i=1;i<=n;i++) cin>>a[i];
    a[n+1]=m;
    R=m/(n+1);

    LL res=0;
    for (int i=0;i<=n;i++)
    {
   
        int l=a[i];//[l,r]在该区间上a[i]的取值相同 
		int r=a[i+1]-1;
        int x=l/R;//[l,r]区间对应的g(x)的取值 
		int y=r/R;
        if (y<=i || x>=i)//若 g(x)每一小段都在a[i]--[l,r]区间的下方---或上方 
        {
   
            res+=abs((LL)i*(r-l+1)-get(l,r));//|f(x)-g(x)| 
        }
        else//有交集时 
        {
   
            int mid=i*R;//交点的最左边 ---i=mid/R 
            res+=abs((LL)i*(mid-l+1)-get(l,mid));  // 左半边        |f(x)-g(x)| 
            res+=abs((LL)i*(r-mid)-get(mid+1,r));  // 右半边        |f(x)-g(x)| 
        }
    }
    cout<<res<<endl;//输出误差 
    return 0;
}

202009-2-csp-风险人群筛查

AcWing 3293. 风险人群筛查

阅读理解:“连续 k 个或更多坐标均位于矩形内(含边界)”是说明last>=k,并不是有>k个不同点位于高危区域内

#include
using namespace std;
const int N=1e3+10;
int n;//居民数 
int k;//连续k个坐标 
int t;//每个居民共t个坐标

int res;//经过人数
int ans;//逗留人数 
int main()
{
   
	int x1,y1,x2,y2;//矩形框的坐标 
	cin>>n>>k>>t>>x1>>y1>>x2>>y2;
	
	while(n--)
	{
   
		bool pass=false;
		bool wait=false;
		int s=0;//记录连续停留时间 
		for(int i=0;i<t;i++)
		{
   
			int x,y;
			cin>>x>>y;
			if(x>=x1 && x<=x2 && y>=y1 && y<=y2)//处在高危地区
			{
   
				s++;
				pass=true;
				if(s>=k)
					wait=true;
			 }
			 else
			 	s=0;	 		
		}
		if(pass)
			res++;
		if(wait)
			ans++; 
			
	}
	cout<<res<<endl<<ans<<endl;
	return 0;
}

201912-2-csp-回收站选址

AcWing 3283. 回收站选址

#include
using namespace std;
const int N =1E3+10;
typedef pair<int,int> PII;
#define x first
#define y second
PII q[N];
int n;
//左上-上-右上-右-右下-下-左下-左 
int dx[8]={
   -1,-1,-1,0,1,1, 1, 0};
int dy[8]={
   -1, 0, 1,1,1,0,-1,-1};
int ans[5];//返回答案
int main()
{
   
	cin>>n;
	for(int i=0;i<n;i++)
		cin>>q[i].x>>q[i].y;
		
	for(int i=0;i<n;i++)
	{
   
		int s[8]={
   0};//存储第i个点的八个方向上---点的信息
		for(int j=0;j<n;j++)
		{
   
			for(int k=0;k<8;k++)
			{
   
				int a=q[i].x+dx[k];
				int b=q[i].y+dy[k];
				if(a==q[j].x && b==q[j].y)//如果某方向上有垃圾
					s[k]++;
			}
		}
		if(s[1] && s[3] && s[5] && s[7])//满足--上下左右都有垃圾
			ans[s[0]+s[2]+s[4]+s[6]]++;
	}
	for(int i=0;i<5;i++)
		cout<<ans[i]<<endl;
	return 0;
}

201909-2-csp-小明种苹果(续)

AcWing 3278. 小明种苹果

你可能感兴趣的:(acwing,算法,c++,图论)