篮球杯软件赛国赛C/C++ 大学 B 组补题

3.gcd 模拟

cpp 复制代码
map<pair<int,int>,int>m;
void solve(){
    int n;cin>>n;
    forr(i,1,n){
        int ux,uy,vx,vy;
        cin>>ux>>uy>>vx>>vy;
        int dx=vx-ux,dy=vy-uy;
        if(dx!=0&&dy!=0){
            int g=abs(__gcd(dx,dy));
            dx/=g,dy/=g;//dxdy中除去公共部分(gcd) 就是相邻整数点的横纵距离
            int nx=ux,ny=uy;
            while (nx!=vx&&ny!=vy){
                m[{nx,ny}]++;
                nx+=dx,ny+=dy;
            }
            m[{vx,vy}]++;
        }else if(dx==0){//处理g=0的情况
            forr(i,min(uy,vy),max(uy,vy)){
                m[{ux,i}]++;
            }
        }else if(dy==0){
            forr(i,min(ux,vx),max(ux,vx)){
                m[{i,uy}]++;
            }
        }
    }
    int ans=0;
    for(auto i:m){
        if(i.second>1){
            ans++;
        }
    }
    cout<<ans<<endl;
}

4. 二分查找

简单的二分查找板子,但是需要注意check函数的细节

cpp 复制代码
void solve(){
    int n,m;cin>>n>>m;
    vector<int>a(n+1);
    int mnd=1e8+10;
    forr(i,1,n){
        cin>>a[i];
        mnd=min(a[i],mnd);
    }
    auto check=[&](int x)->bool{
        int pre=0,cnt=0,fg=0;
        forr(i,1,n){
            int dis=a[i]-pre;
            if(dis>x){
        //注意中间添加检查点的个数
        if(dis%x==0)cnt+=dis/x-1;
        else cnt+=dis/x;
            }
            pre=a[i];
        }
        return cnt<=m+1;//爆发技能就相当于多加一个检查点
    };
    int l=1,r=1e8+10;
    while (l<r)
    {
        int mid=(l+r)>>1;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    cout<<r<<endl;
}

5.贪心

贪心,每次往前放最小的 新添加的要放在原字符串中更大的字母的前面

cpp 复制代码
void solve(){
    int n,m;cin>>n>>m;
    string s,c;cin>>s>>c;
    sort(c.begin(),c.end());
    int i,j;
    string ans;
    for(i=0,j=0;i<n&&j<m;)
    {
        if(s[i]<=c[j])ans+=s[i++];
        else ans+=c[j++];
    }
    while (i<n)ans+=s[i++];
    while (j<m)ans+=c[j++];
    cout<<ans<<endl;
}

6. dp

数据量不大 1e6 三维dp 数组元素已经用了多少反转区间本元素是否反转

逆转贡献时间复杂度不大 1 e 9 ≈ 2 30 1e9≈2^{30} 1e9≈230

cpp 复制代码
const int N=1e3+10;
int twos[35];
int rev(int x){
    int ans=0,pre=x;
    stack<bool>b;
    while (x)
    {
        b.push(x&1);
        x>>=1;
    }
    int i=0;
    while (!b.empty())
    {
       ans+=b.top()*twos[i++];
       b.pop();
    }
    // cout<<ans<<' ';
    // cout<<ans-pre<<endl;
    return ans-pre;
}
int dp[N][N][2];
void solve(){
    twos[0]=1;
    forr(i,1,31)twos[i]=twos[i-1]*2;
    int n,m;
    cin>>n>>m;
    vector<int>a(n+1),b(n+1);
    int sum=0;
    forr(i,1,n){
        cin>>a[i];
        sum+=a[i];
        b[i]=rev(a[i]);//逆转后的贡献
    }
    
    forr(i,1,n){
        forr(j,1,m){
            dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]);//不用反转
            dp[i][j][1]=max(dp[i-1][j][1],dp[i-1][j-1][0])+b[i];//反转  
            //如果上一个没转,本次新开反转区间 
            //如果上一个反转了,延续上个区间
        }
    }
    // cout<<sum<<endl;
    cout<<max(dp[n][m][0],dp[n][m][1])+sum<<endl;
}

7.贪心 滑动窗口

注意平面是第一象限0,1e8的正方形

贪心(纵):最优情况是以每个圆的下边界为底往上+h

滑动窗口(横):排序 滑动窗口找长度为w的区间 能包含的圆最多

cpp 复制代码
struct cir{
    int x,y,r;
};
//贪心思想(纵)+滑动窗口(横)
void solve(){
    int n,w,h;cin>>n>>w>>h;
    vector<cir>a(n+1);
    vector<int>yl;
    forr(i,1,n){
        cin>>a[i].x>>a[i].y>>a[i].r;
        yl.push_back(a[i].y-a[i].r);//贪心 最优情况是以每个圆的下边界为底
    }
    sort(a.begin()+1,a.end(),[](cir cx,cir cy){
        return cx.x+cx.r<cy.x+cy.r;
    });//从小到大 右端排序
    int ans=0;
    
    //在纵向区间内,枚举横边,计数
    auto cnt=[&](int w,int h,int cury)->void{
        priority_queue<int,vector<int>,greater<int>>q;//小根堆 顶上是最左边的边
        forr(i,1,n){
            if(a[i].y-a[i].r>=cury&&a[i].y+a[i].r<=cury+h){//如果在纵坐标h的区间内
                q.push(a[i].x-a[i].r);
                while (!q.empty()&&a[i].x+a[i].r-q.top()>w)q.pop();//滑动窗口 优先队列维护横坐标
                ans=max(ans,(int)q.size());
            }
        }
    };
    forr(i,1,n){
        cnt(w,h,yl[i]);
        cnt(h,w,yl[i]);
    }
    cout<<ans<<endl;
}

8.递推

借鉴(抄袭)了dalao的思路

  • 每个位置都有两种跳法 2 i 2i 2i和 i + c i i+c_i i+ci
  • 就像二叉树的结构,从叶子往根递推,记录哪个位置当根set.size()最大
  • 问的是"可能经过的",所以 2 i 2i 2i和 i + c i i+c_i i+ci能跳则权值放入set
  • 数据很水,用set也能过,感觉是 n 2 n^2 n2的复杂度;dalao的题解中用bitset取或运算代替set.insert记录权值,很快
cpp 复制代码
const int N=4e4+5,M=130;
set<int>s[N];

void solve(){
	int n;cin>>n;
	vector<int>a(n+1);
	forr(i,1,n)cin>>a[i];
	int ans=0;
	reforr(i,1,n){
		s[i].insert(a[i]);
		if(a[i]+i<=n){
      for(auto j:s[i+a[i]])s[i].insert(j);
    }
		if(2*i<=n){
      for(auto j:s[i*2])s[i].insert(j);
    }
		ans=max(ans,(int)s[i].size());
	}
	cout<<ans<<endl;
}
相关推荐
汉克老师1 小时前
CSP-J 初赛(以满分为目标):第三十九课《数学与逻辑②——阶乘、排列数与组合数:公式到底从哪里来?》
c++·csp-j·小学生·学c++编程
水饺编程1 小时前
第5章,[Win32 章节] :在平面直角坐标系中描点
c语言·c++·windows·visual studio
linx2951 小时前
单元九 · 零基础路线图-第 7–9 周·类与 RAII
c语言·开发语言·数据结构·c++·嵌入式硬件·算法
无忧.芙桃1 小时前
嵌入式(一):嵌入式历史与计算机基础:从 ENIAC 到 MCU 四大技术方向
c语言·单片机·嵌入式硬件·计算机
布莱克6051 小时前
C++ 七大排序算法详解:选择、冒泡、插入、计数、堆、快速与归并排序
数据结构·c++·算法·排序算法
一只旭宝1 小时前
Python 与 C/C++ 内存模型对比总结
c语言·c++·python
心态还需努力呀2 小时前
把 Flameshot 编译进鸿蒙 PC:一次 Qt C++ 截图工具的源码级移植实战
c++·qt·harmonyos
白色的北极熊2 小时前
c语言 输出菱形字符串
c语言·开发语言
科学实验家2 小时前
最小生成树:Prim,kruskal
数据结构·c++·算法
学习智者3 小时前
《玄》IDE v3.6.3重磅发布:全功能修复与性能飞跃
开发语言·c++·ide·算法·中文语言 玄