河南萌新联赛2024第(四)场:河南理工大学

【牛客】河南萌新联赛2024第(四)场:河南理工大学

不按顺序写:

D:

题目大意:给n个数字,判断是不是素数

思路:注意262144K=256MB N=1e8跑一个欧拉筛 然后不用二分,新建一个is__prime数组记录就好了 O(1)的判断

#include<iostream>
#include <cstdio>
#define lld long long 
const int N =1e8+9;
bool is_prime[N],is__prime[N];
int prime[N],n,cnt;
using namespace std;
void Euler(int x){
    for(int i=2;i<=x;++i){
      if( !is_prime[i] )  prime[++cnt]=i,is__prime[i]=1;
      for(int j=1 ; j<=cnt && i*prime[j]<=x ; ++j){
         is_prime[ i * prime[j] ]=true;
         if( i % prime[j]== 0) break;
      }
    }
}
bool check(int x){
    int L=1,R=cnt;
    while(L <= R){
        int mid = L + (R-L)/2;
        if(prime[mid] == x) return true;
        else if(prime[mid] < x)
            L = mid+1;
        else 
            R = mid-1;
    }
    return false;
}
int main()
{
   int n;
   cin>>n;
   Euler(N);

   for(int i=1;i<=n;++i){
        int x;
        cin>>x;
        if(is__prime[x]) cout<<"Yes";
        else cout<<"No";
        cout<<"\n";
   }
   return 0;
}

E

大意:给一个区间[L,R] 回答两个问题 1.有多少素数 2.多少个子区间&起来的的值为0

思路:先跑个1e8的线性筛 问题一:lower_bound跑第一个​大于等于L的下标L__ ,upper_bound跑第一个大于R的下标R__,这样就免去了+1 比如[2,3,5,7,11,13] 让你求[4,14]和[4,13]会发现跑upper_bound不用判断右端点是不是素数,答案就是 R__-L__

问题二:


/*
2之外的所有素数都是奇数,也就是说都是以1结尾的二进制
所以必须有2
接上文,如果primes[L__]不是2 输出0
简单枚举一下:
0000010  : 2
0000011  : 3
0000101  : 5
0000111  : 7
0001011 : 11
发现 2&3=2 不行
特判一下 如果只有两个素数  或者没有2 输出0
2&3&5=0
2&5&7=0
所以第一问的长度减去2就好了
*/
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

#define lld long long 
const int N = 1e8 + 9;
bool is_prime[N];
int primes[N];
int cnt=0;
void Euler(int x) {
    for (int i = 2; i <= x; ++i) {
        if (!is_prime[i]) {
            primes[++cnt]=i;
        }
        for (int j = 1; j <=cnt && i * primes[j] <= x; ++j) {
            is_prime[i * primes[j]] = true;
            if (i % primes[j] == 0) break;
        }
    }
}
void solve() {
    int L, R;
    cin >> L >> R;
    vector<int> prime__;
    int l__ = lower_bound(primes+1, primes+1+cnt, L)-primes;
    int r__ = upper_bound(primes+1, primes+1+cnt, R)-primes;
    int ans = r__ - l__;
    cout << ans << " ";
    if(l__!=1 or ans<=2) cout<<"0";
    else{
        cout<<ans-2;
    }
    cout<<"\n";
}

int main() {
    int T;
    cin >> T;
    Euler(N);
    while (T--) {
        solve();
    }
    return 0;
}



F:

大意:给一个字符表达式形如 111+999999+22 求值 和按照数字从大到小排列字符

思路:跑一遍字符 没遇到加号就把数字存到x中,然后计算x的值,接着存到一个数组num里,"+"的数量比数字少 单独在计算一次 最后sort数组num就行

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <algorithm>
#define lld long long 
#define ios std::ios::sync_with_stdio(false);std::cin.tie(0); 

using namespace std;

void turn(string& x, lld& result, vector<lld>& num) {
    lld R = 0;
    int len = x.size();
    for(int i = 0; i < len; ++i) {
        R = R * 10 + (x[i] - '0');
    }
    result += R;
    num.push_back(R);
}
bool cmp(int a,int b){
    return a>b;
}
void solve() {
    string s, x;
    lld result = 0;
    vector<lld> num;
    cin >> s;
    for(int i = 0; i < s.size(); ++i) {
        if(s[i] != '+') {
            x.push_back(s[i]);
        }
        if(s[i] == '+') {
            turn(x, result, num);
            x.clear();
        }
    }
    //加号后面还有数字没处理
    turn(x, result, num);
    
    
    sort(num.begin(), num.end(),cmp);
    int len_ = num.size()-2;
    for(int i = 0; i <= len_; ++i) {
        cout << num[i];
        cout<<"+";
    }
    //最后一个数字单独输出
    cout<<num[len_+1];

    cout << "\n" << result << "\n";
}

int main() {
    ios;
    int T = 1;
    while(T--) {
        solve();
    }
    return 0;
}

H:

大意:一个傻逼贪心题目 x个金币 n个人 你作为一号 每个人都想获得更多的金币,你可以随意选取金币 选完后所有人投票,一半人投票通过你才能获得金币,求你能获得的最多金币

思路:尤其傻逼的题目 你只需要给一半的人分配1个金币就可以获得他们的投票,然后判断奇数偶数就好了 举例 x=100 n=5 分配成[98,1,1,0,0]就行 x=100,n=6 分配成[98,1,1,0,0,0] 保证过一办就行

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    int t;
    cin >> t;
    while (t--) {
        int x, n;
        cin >> x >> n;
        
        // 计算通过提案所需的最少票数
        int len=0;
        if(n%2==0)
            len = n/2;
        else 
            len = (n / 2) + 1;
        
        // 计算需要给出的金币数量
        int coions = len - 1; // 给每个需要投票支持的恶魔发1个金币
        
        // 剩下的金币都归你自己
        int ans = x - coions;
        
        cout << ans << "\n";
    }

    return 0;
}

J:

大意:给出一棵有根树,根是root 每个节点可以到达自己的任意子节点 对于Fib数列定义为 F1=1,F2=2,Fi=Fi−1+Fi−2 给出Q个询问 每次两个数 x,k 生成一个集合{x+Fi,i>=k x+Fi <=n} 的一些点 求一个节点U 能到达集合中的所有点且U距离根root最远

\[\begin{align} & 先跑出F_i的值,然后对于每个询问x,k跑出集合S \\ & 注意到能到达这个集合中的所有点必然是他们的\bigcup_{v,u\in } \text{LCA}(u,v) \\ & 循环跑S一遍就出来了,因为F_i的值很大,不会超过30次\\ & 注意判断S集合的元素个数,0个就输出0,\\ &\color{red}\text{LCA}记得\text{Tarjan}\quad虽然这个题目倍增也可以跑\\ \end{align} \]

#include <iostream>
#include <vector>
#include <cmath>
#include <cstring>
using namespace std;

#define ios std::ios::sync_with_stdio(false); std::cin.tie(0);
const int N = 1e5 + 9;

int n, Q, root;
int logn;
vector<vector<int>> anc;
vector<int> depth;
vector<int> head;
vector<struct node> e;

struct node {
    int to, val, next;
};

void add(int u, int v, int val) {
    static int idx = 0;
    e[idx] = {v, val, head[u]};
    head[u] = idx++;
}

void bd() {
    cin >> n >> root >> Q;
    logn = log2(n);
    head.assign(n + 1, -1);
    e.resize(2 * (n - 1)); // Adjust size based on the number of edges
    anc.assign(n + 1, vector<int>(logn + 1, -1));
    depth.assign(n + 1, 0);

    for (int i = 1; i <= n - 1; ++i) {
        int u, v;
        cin >> u >> v;
        add(u, v, 0);
        add(v, u, 0);
    }
}

void dfs(int u, int fa) {
    anc[u][0] = fa;
    for (int i = head[u]; i != -1; i = e[i].next) {
        int v = e[i].to;
        if (v == fa) continue;
        depth[v] = depth[u] + 1;
        dfs(v, u);
    }
}

void init() {
    for (int j = 1; j <= logn; ++j) {
        for (int i = 1; i <= n; ++i) {
            int v = anc[i][j - 1];
            if (v != -1) {
                anc[i][j] = anc[v][j - 1];
            }
        }
    }
}

int LCA(int u, int v) {
    if (depth[v] > depth[u])
        swap(u, v);
    for (int i = logn; i >= 0; --i) {
        if (depth[u] - (1 << i) >= depth[v]) {
            u = anc[u][i];
        }
    }
    if (u == v) return u;
    for (int i = logn; i >= 0; --i) {
        if (anc[u][i] != anc[v][i]) {
            u = anc[u][i];
            v = anc[v][i];
        }
    }
    return anc[u][0];
}

vector<int> F(N);

void f() {
    F[1] = 1;
    F[2] = 2;
    int x = 2;
    while (1) {
        F[x + 1] = F[x] + F[x - 1];
        x++;
        if (F[x] > n) break;
    }
}

void solve(int u, int v) {
    if(v>30){
        cout<<"0"<<"\n";
        return ;
    }
    vector<int> S;
    int pos = v;
    while (u + F[pos] <= n) {
        S.push_back(u + F[pos]);
        pos++;
        if (u + F[pos] > n) break;
    }
    if (S.empty()) {
        cout << "0";
    } else {
        if (S.size() == 1) {
            cout << S[0];
        } else {
            int ans = LCA(S[0], S[1]);
            for (size_t k = 2; k < S.size(); ++k) {
                ans = LCA(ans, S[k]);
            }
            cout << ans;
        }
    }
    cout << "\n";
}

int main() {
    ios;
    bd();
    f();
    dfs(root, -1);
    init();
    for (int i = 1; i <= Q; ++i) {
        int u, v;
        cin >> u >> v;
        solve(u, v);
    }
    return 0;
}

posted @ 2024-08-08 13:55  phrink  阅读(84)  评论(0)    收藏  举报