【题解】CF11 合集

前言:

  1. 本人不会 LaTeX……请见谅
  2. 码风奇特,不喜勿喷哈
  3. 题面翻译取自 luogu,本蒟蒻也会安置原题链接
  4. 保证文章中不出现“显然”或者“注意到”,可能会出现“易证”
  5. AC 代码会放置在每一个题目的最底端,为防止 ban 码的情况出现,不设置跳转链接
  6. 有写错的地方欢迎各位神犇指正
  7. 本套题共 5 道,预计阅读 + 理解时间小于 1h(红黄蓝蓝紫)

正片开始!

CF11A

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

今天照常~7:45 开始刷 CF,打了 CF11A 的 100 分正解……
——lmy

签到题,应该没有人不会吧!

推理过程:

  • 按题意直接模拟会 TLE(别问我怎么知道的)
  • 考虑到在遥远的小学数学中,老师亲切地告诉我们乘法的来由
  • 嗯~做完了

细节处理:

代码:

点击查看代码
#include<iostream>
using namespace std;
const int maxn=2048;
int n,d,ans,a[maxn];
signed main(){
	cin>>n>>d;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n-1;i++){
		if(a[i]>=a[i+1]){
			ans+=(a[i]-a[i+1])/d+1;
			a[i+1]+=((a[i]-a[i+1])/d+1)*d;
		}
	}
	cout<<ans<<endl;
	return 0;
}

完结撒花!

--------------------云落的分割线--------------------

CF11B

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

难度:黄题

无聊的思维题

推理过程:

  • 题意转化求一个 Σi=1ni×Si=x,其中 iNSi=±1
  • 嗯,考虑当 x=Σi=1ni 的时候,答案即为 n
  • 那么,若 xΣi=1ni,则寻找一个 n,使得 x<Σi=1nix>Σi=1n1i
  • 又是我们快乐的分类讨论环节
  • 注意到如果我们将一个 Si=1 转化为 Si=1,那么我们会获得 2i 的贡献
  • 由奇偶性进行分讨,令Σi=1i=ni=x+k
  1. k0(mod 2),令 i=k/2,则当 Si=1 时,Σi=1ni×Si=x,答案就是这个 n
  2. k1(mod 2),让 nn+1 直到满足进入第 1 类情况

细节处理:

  • x 可能为负,注意判断
  • 时间复杂度有保证,本题不卡常,随便写

代码:

比 T1 都短小精悍的代码呢!

点击查看代码
#include<iostream>
using namespace std;
int n,ans;
int main(){
	cin>>n;
	if(n<0){
		n=-n;
	}
	int cnt=0;
	for(int i=1;;i++){
		if(cnt==n||cnt>n&&(cnt-n)%2==0){
			ans=i-1;
			break;
		}
		cnt+=i;
	}
	cout<<ans<<endl;
	return 0;
}

完结撒花!

--------------------云落的分割线--------------------

CF11C

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

难度:蓝题(可能是个黄?)

搜索的垃圾题目,其实 dfs 掌握熟练的神犇们可以一眼秒

推理过程:

  • 枚举每一个正方形的左上角坐标,然后依次扫描四条边的长度
  • 由题意,可以平行扫描和斜向扫描,分开处理
  • 重点是判断
  • 首先,正方形四边相等
  • 其次,注意到题目要求每个被计入贡献的正方形是独立的(即互不连通),所以还要 dfs 处理连通块,统计该连通块大小是否与当前正方形中 1 的个数相等

细节处理:

  • 边长不小于 2,如图示:边长为 2 的正方形

1 1 1
1 0 1
1 1 1

  • 注意是八连通判断!

代码:

点击查看代码
#include<iostream>
#define endl '\n'
#define int long long
using namespace std;
const int maxn=256;
const int dx[]={-1,1,0,0,-1,-1,1,1},dy[]={0,0,-1,1,-1,1,-1,1};
int n,m;
char s[maxn][maxn];
inline int dfs1(int x,int y){
	int a=1,b=1,c=1,d=1;
	while(x+1<=n&&s[x+1][y]=='1'){
		x++;
		a++;
	}
	while(y+1<=m&&s[x][y+1]=='1'){
		y++;
		b++;
	}
	while(x-1>0&&s[x-1][y]=='1'){
		x--;
		c++;
	}
	while(y-1>0&&s[x][y-1]=='1'){
		y--;
		d++;
	}
	if(a==b&&c==d&&a==c){
		return a;
	}
	return 0;
}
inline int dfs2(int x,int y){
	int a=1,b=1,c=1,d=1;
	while(x+1<=n&&y-1>0&&s[x+1][y-1]=='1'){
		x++;
		y--;
		a++;
	}
	while(x+1<=n&&y+1<=m&&s[x+1][y+1]=='1'){
		x++;
		y++;
		b++;
	}
	while(x-1>0&&y+1<=m&&s[x-1][y+1]=='1'){
		x--;
		y++;
		c++;
	}
	while(x-1>0&&y-1>0&&s[x-1][y-1]=='1'){
		x--;
		y--;
		d++;
	}
	if(a==b&&b==c&&c==d){
		return a;
	}
	return 0;
}
inline bool inbound(int x,int y){
	return x>=1&&x<=n&&y>=1&&y<=m;
}
inline int dfs(int x,int y){
	s[x][y]='0';
	int res=1;
	for(int i=0;i<8;i++){
		int nx=x+dx[i],ny=y+dy[i];
		if(inbound(nx,ny)&&s[nx][ny]=='1'){
			res+=dfs(nx,ny);
		}
	}
	return res;
}
signed main(){
	int T;
	cin>>T;
	while(T--){
		cin>>n>>m;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				cin>>s[i][j];
			}
		}
		int ans=0;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				if(s[i][j]=='1'){
					int a=dfs1(i,j),b=dfs2(i,j);
					int w=dfs(i,j);
					if(w==4*(a-1)||w==4*(b-1)){
						ans++;
					}
				}
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

--------------------云落的分割线--------------------

CF11D

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

可恶的状压 dp

推理过程:

  • 注意到 n≤19,考虑状压 dp
  • 钦定一个 dp[i][j],其中 i 这一维是需要状压的,用来记录 19 个节点每一个是否已经走过(走过为 1 ,没走为 0,用二进制压缩一下即可)
  • 同时,我们认为状压中已经走过的序号最小的节点为出发节点,j 即数组第二维是路径终点(当这两个数相同时,说明找到了一个环)
  • 转移方程: dp[k][i(1<<k1)]=Σdp[j][i]

细节处理:

  • 考虑到 ans 会重复最后输出的时候要去重哦
  • 不开___________!

代码:

讲的很详细了,注释就不写了

点击查看代码
#include<iostream>
#define int long long
using namespace std;
const int maxn=20;
int n,m,dp[maxn][1<<maxn],ans;
bool g[maxn][maxn];
inline int lowbit(int x){
	return x&-x;
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;++i){
		int x,y;
		cin>>x>>y;
		g[x][y]=g[y][x]=1;
	}
	for(int i=1;i<=n;++i){
		dp[i][1<<(i-1)]=1;
	}
	for(int i=0;i<(1<<n);i++){
		for(int j=1;j<=n;j++){
			for(int k=1;k<=n;++k){
				if(!g[k][j]||lowbit(i)>(1<<(k-1))){
					continue;
				} 
				if((1<<(k-1))&i){
					if((1<<(k-1))==lowbit(i)){
						ans+=dp[j][i];
					}
				}else{
					dp[k][i^1<<(k-1)]+=dp[j][i];
				}
			}
		}
	}
	cout<<(ans-m)/2<<endl;
	return 0;
}

--------------------云落的分割线--------------------

CF11E

题面(可从下方链接跳转看原题题面):

题目传送门

序言 & 结论:

难度:紫题(呜呜呜┭┮﹏┭┮,好难啊)

前置知识:01 分数规划

推理过程:

  • 求分数,先浅浅二分一下
  • 重点是 check 函数部分
  • 首先我们预处理一下,把所有不可能的地方的 X 先填上
  • 而对于首尾相邻的情况,这就需要考虑到最后的匹配率情况来进行 X 的添加。如果首尾是 LL,那么将 X 加在最后是优的;如果是 RR,那么 X 加在开头是优的
  • 显然的贪心结论:在进行我们的算法之前,我们需要知道一个事实:改变后的新字符串长度为偶数最佳
  • 如果长度为奇数最佳,那么我们将其倍长后会发现,前后串对应的 LR 是错开的,那么得到的最大匹配率就会等于 (cntL+cntR)/(2×len)
  • 其实可以对 cntLcntR 分类讨论一下,都可以推出上述假设不成立的结论
  • 设 dp[i][0/1] 表示当前匹配到原串的第 i 位,且当前位教官的命令是 R/L 时的最大权值
  • 转移方程见代码!

细节处理:

  • 本题卡常,cin cout 会被卡
  • 实数意义下二分有 eps!

代码:

备花!

点击查看代码
#pragma GCC optimize("Ofast,unroll-loops")
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e6+10;
const double eps=1e-9;
int n,tot;
char s[maxn],p[maxn];
double dp[maxn<<1][2];
inline bool check(double x){
	dp[0][0]=-x;
	dp[0][1]=0;
	for(int i=1;i<=tot;i++){
		dp[i][0]=dp[i-1][1]+(p[i]=='L')-x;
		dp[i][1]=dp[i-1][0]+(p[i]=='R')-x;
		dp[i][0]=max(dp[i][0],dp[i][1]-x);
		dp[i][1]=max(dp[i][1],dp[i][0]-x);
	}
	return dp[tot][1]>=0;
}
int main(){
	scanf("%s",s+1);
	n=strlen(s+1);
	if(s[1]=='R'&&s[n]=='R'){
		p[++tot]='X';
	}
	p[++tot]=s[1];
	for(int i=2;i<=n;i++){
		if(s[i]!='X'&&s[i]==s[i-1]){
			p[++tot]='X';
		}
		p[++tot]=s[i];
	}
	if(s[1]=='L'&&s[n]=='L'){
		p[++tot]='X';
	}
	double l=0,r=100;
	while(l+eps<r){
		double mid=(l+r)/2;
		if(check(mid/100)){
			l=mid;
		}else{
			r=mid;
		}
	}
	printf("%.6lf",(int)(r*1e6)/1e6);
	return 0;
}

完结撒花!

posted @   sunxuhetai  阅读(85)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示