【题解】CF11 合集
前言:
- 本人不会 LaTeX……请见谅
- 码风奇特,不喜勿喷哈
- 题面翻译取自 luogu,本蒟蒻也会安置原题链接
- 保证文章中不出现“显然”或者“注意到”,可能会出现“易证”
- AC 代码会放置在每一个题目的最底端,为防止 ban 码的情况出现,不设置跳转链接
- 有写错的地方欢迎各位神犇指正
- 本套题共 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
题面(可从下方链接跳转看原题题面):
序言 & 结论:
难度:黄题
无聊的思维题
推理过程:
- 题意转化求一个
,其中 且 - 嗯,考虑当
的时候,答案即为 n - 那么,若
,则寻找一个 n,使得 且 - 又是我们快乐的分类讨论环节
- 注意到如果我们将一个
转化为 ,那么我们会获得 的贡献 - 由奇偶性进行分讨,令
- 当
,令 ,则当 时, ,答案就是这个 n - 当
,让 直到满足进入第 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 处理连通块,统计该连通块大小是否与当前正方形中
的个数相等
细节处理:
- 边长不小于 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 即数组第二维是路径终点(当这两个数相同时,说明找到了一个环)
- 转移方程:
细节处理:
- 考虑到 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 是错开的,那么得到的最大匹配率就会等于
- 其实可以对
与 分类讨论一下,都可以推出上述假设不成立的结论 - 设 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;
}
完结撒花!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具