当前位置: 首页 > news >正文

3.23周赛补题

感觉还要多练,有的题思路不难,但是赛时就没思路。

A

const int N=110,M=1e4+10;
int dp[N][M];
void solve(){
    int n,m;
    cin>>n>>m;
    vector<int>a(n+1);
    forr(i,1,n){
        cin>>a[i];
    }
    dp[0][0]=1;//没钱 没菜 就是一种情况
    forr(i,1,n){
        reforr(j,0,m){
            dp[i][j]=dp[i-1][j];//没买
            if(j>=a[i])dp[i][j]+=dp[i-1][j-a[i]];//买了
        }
    }
    // forr(i,1,n){
    //     forr(j,1,m)cout<<dp[i][j]<<' ';
    //     cout<<endl;
    // }
    cout<<dp[n][m];
}

E

  • 注意 x , y x,y x,y是两个非负整数
  • ∣ x 2 + y 2 − D ∣ \lvert x^2+y^2-D\rvert x2+y2D最小,就是找 x 2 + y 2 x^2+y^2 x2+y2最接近 D D D
  • x 2 + y 2 = D x^2+y^2=D x2+y2=D,用一个数表示另一个数 x = D − y 2 x=\sqrt{D-y^2} x=Dy2
    • 如果 x 2 + y 2 ≤ D x^2+y^2\leq D x2+y2D x = ⌊ D − y 2 ⌋ x=\lfloor\sqrt{D-y^2}\rfloor x=Dy2
    • 要么 x 2 + y 2 ≥ D x^2+y^2\geq D x2+y2D x = ⌈ D − y 2 ⌉ x=\lceil\sqrt{D-y^2}\rceil x=Dy2
  • 这是最接近 D D D x x x的取值 看这两种那个离 D D D最近
  • 并且这也限制了 0 < y < D 0<y<\sqrt{D} 0<y<D

两个正整数这类的题,这两变量一定会相互牵制,缩小范围

const int N=2e12;
void solve(){
    int d;cin>>d;
    int ans=N;
    for(int y=1;y*y<=d;y++){
        int xc=ceil(sqrt(d-y*y));
        int xf=floor(sqrt(d-y*y));
        ans=min(min(abs(xc*xc+y*y-d),abs(xf*xf+y*y-d)),ans);
    }
    cout<<ans<<endl;
}

G

打赛的时候没读明白题

题意

找一条路径走四个点 中间跳两次 中间两个点不能被跳过

思路

  • 确定 一个路径及其两头的点 为中间经过的点
  • 这两头的点度数都应该 ≥ 2 \geq 2 2
  • 再从两头的点确定起点和终点
const int N=1e4+10,M=1e5+10;
int n,m;
int u[M],v[M];
map<int,int>deg;
void solve(){
    cin>>n>>m;
    forr(i,1,m){
        cin>>u[i]>>v[i];
        deg[v[i]]++,deg[u[i]]++;
    }
    // for(auto i:deg)cout<<i.first<<' '<<i.second<<endl;
    int ans=0;
    forr(i,1,m){
        ans+=((deg[u[i]]-1)*(deg[v[i]]-1));
    }cout<<ans*2<<endl;//逆转也可以是一种解 别急 有反转
}

J

一开始的模拟做法tle了
所以需要一步给出应该达到的数字

set做法

set方法lower_bound(int a) 返回第一个大于等于a的数的迭代器位置

set<int>s;
void solve(){
  //set存没出现过的数字
    forr(i,1,1e5+1e6)s.insert(i);//极限情况 1e5个数都是1e6
    int n;
    cin>>n;
    forr(i,1,n){
        // cin>>a[i];
        int a;cin>>a;
        set<int>::iterator it=s.lower_bound(a);
        s.erase(*it);//去除出现过的数字
        cout<<*it<<' ';
    }cout<<endl;
}

并查集做法

  • 初始化 每个数 a i a_i ai的根就是自身
  • 每次出现过某数 a i a_i ai 就让fa[ a i a_i ai]= a i a_i ai现在的根+1
  • 此时fa[ a i a_i ai]的数可能也会和前面的重复 但是还会再find()一次 找到的根一定是不会重复的
    更详细的过程
const int N=1e5+1e6;
int fa[N];
int find(int x){
    if(x==fa[x])return x;
    return fa[x]=find(fa[x]);
}
void solve(){
    forr(i,1,1e5+1e6)fa[i]=i;
    int n;
    cin>>n;
    forr(i,1,n){
        int a;cin>>a;
        int f=find(a);
        fa[f]=find(f)+1;
        cout<<f<<' ';
    }
}

相关文章:

  • C#:第一性原理理解日志(log)
  • 从零实现Json-Rpc框架】- 项目实现 - 基于Dispatcher模块的RPC框架
  • `git commit --amend` 详解:修改提交记录的正确方式
  • Content-Type设置内容类型
  • React受控表单绑定
  • wx201基于ssm+vue+uniapp的购物系统设计与实现小程序
  • J2EE框架技术 第二章 Maven环境搭建及使用
  • 向字符串添加空格
  • JavaScript函数-函数的概念
  • 列表,元组,字典,集合,之间的嵌套关系
  • LLM中的KV Cache优化技术
  • MATLAB语言的链表反转
  • cline源码分析 ---2
  • 漏洞挖掘---灵当CRM客户管理系统getOrderList SQL注入漏洞
  • 【MinIO】对象存储核心概念
  • linux中jar命令
  • C++之输入与输出
  • 【MySQL基础-17】MySQL数字函数详解:从基础到高级应用
  • Arthas线上问题诊断器
  • 进程相关概念