【CSP-M4】

T1

在这里插入图片描述

题解

对于每一个数,循环每一位统计不同数的个数,判断是否小于k,是则答案数+1

代码

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<iomanip>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define mem(a,s) memset(a,s,sizeof(a))
typedef long long LL;
const int N=1e6;
int n,k;
bool sum[10];
int main(){
    //freopen("in.txt","r",stdin);
    cin.sync_with_stdio(false);
    cin >> n >> k;
    int ans = 0;
    rep(i,1,n){
        string s;
        mem(sum, 0);
        cin >> s;
        for(auto it:s)
            sum[it - '0'] = 1;
        int tt = 0;
        rep(i, 0, 9) if (sum[i])
            tt++;
        if(tt<k)
            ans++;
    }
    cout << ans;
    return 0;
}

T2

在这里插入图片描述

题解

这个题不是最小圆覆盖!!不是!!不是!!
一开始浪费了很多时间,后来才发现是“中心位于发射点上”。
这样的话我们直接枚举每一个中心,求取和其他点最大距离,之后求出这些最大距离中的最小距离。
由于输出平方,整个过程中用不到浮点类型,所以最后直接输出lld+后缀.00即可

代码

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<iomanip>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define mem(a,s) memset(a,s,sizeof(a))
typedef long long LL;
const int N=1000+10;
pair<LL,LL> a[N];
int n;
int main(){
    //freopen("in.txt","r",stdin);
    cin.sync_with_stdio(false);
    cin>>n;
    rep(i,1,n)
        cin >> a[i].first >> a[i].second;
    if(n==1){
        cout << a[1].first <<".00"<< ' ' << a[1].second  <<".00"<< endl;
        cout << "0.00";
        return 0;
    }
    sort(a + 1, a + n + 1);
    LL mn=-1, idx;
    rep(i,1,n){
        LL mx = 0;
        rep(j,1,n){
            LL r=(a[i].second - a[j].second) * (a[i].second - a[j].second) + (a[i].first - a[j].first) * (a[i].first - a[j].first);
            if(r>mx)
                mx = r;
        }
        if(mn==-1||mx<mn)
            mn = mx, idx = i;
    }
    cout << a[idx].first <<".00"<< ' ' << a[idx].second  <<".00"<< endl;
    cout << mn << ".00";
    return 0;
}

T3

在这里插入图片描述

在这里插入图片描述

题解

求解有没有满足条件的树,考虑枚举每一种树,每一个节点做根的情况下,依据二叉搜索树的性质,左子树都比根小,右子树都比根大,即左子树就是当前根左边区间的元素,右子树就是当前右边区间的元素,也就是说我们只需要求出每一个区间的情况即可,这就是区间dp,dp[l][r][root]代表节点为a[l,[r][根为root(root属于a[l,r])的子树是否可以构造出满足条件的,则转移方程为dp[l][r][k]=dp[l][k-1][x]&&dp[k+1][r][y]&&gcd[x][k]>1&&gcd[k][y]>1,但是这样复杂度太高了,有没有优化的做法?我们可以发现k这个状态是可以合并的因为我们在枚举k的过程中,每一个子状态都是要么以右边邻近节点为根成为左子树,要么以左边邻近节点为根成为右子树,这样我们其实可以在子状态枚举k的过程中就求出能和左边or右边构造成功的可能,这样状态就缩减成dp[l][r][2],转移方式见代码
注意!!存在k=l,k=r这两种边缘情况,即一个子树为空,这个需要特殊判断!!
最后需要再枚举一遍以每一个元素为根的情况,因为dp[1][n]的两个状态不存在。

代码

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<iomanip>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define mem(a,s) memset(a,s,sizeof(a))
typedef long long LL;
const int N=710;
int n;
int a[N];
int cal[N][N];
bool dp[N][N][2];
int gcd(int x,int y){return y == 0 ? x : gcd(y,x%y);}
int main(){
    //freopen("in.txt","r",stdin);
    cin.sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--){
        cin >> n;
        rep(i,1,n)
            cin>>a[i];
        if(n==1){
            cout << "Yes";
            if(T>=1)
                cout << endl;
            continue;
        }
        rep(i, 1, n)
            rep(j, 1, n)
                cal[i][j] = gcd(a[i], a[j]);
        mem(dp, 0);
        rep(siz,1,n){
            rep(l,1,n-siz+1){
                int r = l + siz - 1;
                rep(k,l,r){
                    if ((k==l||dp[l][k - 1][1])&&(k==r||dp[k + 1][r][0])){
                        if(l!=1&&cal[l-1][k]>1)
                            dp[l][r][0] = 1;
                        if(r!=n&&cal[k][r+1]>1)
                            dp[l][r][1] = 1;

                    }
                }
            }
        }
        bool jud=0;
        rep(k,1,n)
            if((k==1||dp[1][k-1][1])&&(k==n||dp[k+1][n][0])){
                jud=1;
                break;
            }
        cout << (jud ? "Yes" : "No");
        if(T>=1)
            cout << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值