EXAM-2018-8-10

F

突然卡了一会的水题

M

这题有点坑
考虑到一个数列的第一个数肯定会有 我们可以贪心的认为最优的方案是一个数列的第一个与另一个数列所有数的和。但是很容易找到反例

1 2 4 5
1 2 4 5
1先跟1 然后与2 然后1与4 而实际上这时的最佳是2与2

这个时候要么是1继续往后遍历另一个数组 要么是轮换到2 2与眼前的数组 2和2之后还是轮到1与4 先预先将第一个数与另一个数列的所有数的和存入优先队列中 然后处理时再将这个数的下一个数与同位置的另一个数列的和存入

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+7;
int s[maxn],p[maxn];
int id[maxn];
struct qnode
{
    ll a;
    ll b;
    int id;
    qnode(ll _v=0,ll _c=0):a(_v),b(_c){}
    bool operator <(const qnode &r)const
    {
        return a+b>r.a+r.b;
    }
};
priority_queue<qnode>Q;
template<class T>
void read(T &res)
{
    res = 0;
    char c = getchar();
    T f = 1;
    while(c < '0' || c > '9')
    {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        res = res * 10 + c - '0';
        c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x)
{
    if(x < 0)
    {
        putchar('-');
        x = -x;
    }
    if(x >= 10)
    {
        out(x / 10);
    }
    putchar('0' + x % 10);
}
int main(){
    int n,ans=0;
    read(n);
    qnode temp(0,0);
    for(int i=1;i<=n;i++){
        read(s[i]);
    }
    for(int i=1;i<=n;i++){
        read(p[i]);
    }
    for(int i=1;i<=n;i++){
        qnode a(s[1],p[i]);
        a.id=1;
        Q.push(a);
    }
    while(ans!=n)
    {
       temp=Q.top();
       Q.pop();
       ans++;
       if(temp.a+temp.b!=0)//防止超出
       out(temp.a+temp.b);
       printf(" ");
       temp.id++;
       temp.a=s[temp.id];
       Q.push(temp);
    }
    return 0;
}

K

一道比较裸的LCA 也比较常见的预处理 就是要预处理50次方的...当时没想到

#include<bits/stdc++.h>
#define mod 998244353ll
const int maxn=300000+10;
using namespace std;
#define ll long long
struct Edge{
    ll v , next;
}e[maxn << 1];
ll power(ll a,ll b){
    ll ans = 1;
    while(b)
    {
        if(b & 1)ans=ans*a%mod;
        b>>=1;
        a = (a*a) % mod;
    }
    return ans % mod;
}
ll n,m,dp[maxn][25],head[maxn<<1],dep[maxn],prf[maxn][55],cnt=0;
void link(ll u , ll v){
    cnt++;
    e[cnt].v = v;
    e[cnt].next =head[u];
    head[u]=cnt;
}
void DFS(ll u , ll fa){
    dep[u] = dep[fa] + 1;
    for(int i = 1;i <= 50;i++){
        prf[u][i] = (prf[fa][i]+power(dep[u],i));
    }
    dp[u][0] = fa;
    for(ll i=head[u];i;i=e[i].next){
        ll v = e[i].v;
        if(v != fa){
            DFS(v , u);
        }
    }
}
ll LCA(ll u,ll v){
    if(dep[u] < dep[v]) swap(u , v);
    for(int i = 19;i >= 0;i--){
        if(dep[u] >= dep[v] + (1 << i)){
            u = dp[u][i];
        }
    }
    if(u==v){
        return u;
    }
    for(int i = 19;i >= 0;i--){
        if(dp[u][i] != dp[v][i]){
            u=dp[u][i];
            v=dp[v][i];
        }
    }
    return dp[u][0];
}
template<class T>
void read(T &res)
{
    res = 0;
    char c = getchar();
    T f = 1;
    while(c < '0' || c > '9')
    {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        res = res * 10 + c - '0';
        c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x)
{
    if(x < 0)
    {
        putchar('-');
        x = -x;
    }
    if(x >= 10)
    {
        out(x / 10);
    }
    putchar('0' + x % 10);
}
int main()
{
    read(n);
    for(ll i = 1;i < n;i++){
        ll u , v;
        read(u) , read(v);
        link(u,v);
        link(v,u);
    }
    dep[1] = -1;
    DFS(1,1);
    for(ll j=1;j<=19;j++)
        for(ll i =1;i<=n;i++)
           if(dp[i][j - 1]) dp[i][j] = dp[dp[i][j-1]][j-1];
    read(m);
    while(m--){
        ll u , v ,k;
        read(u),read(v),read(k);
        ll an = LCA(u,v);
        out(((prf[u][k] + prf[v][k]) - (prf[an][k] + prf[dp[an][0]][k])) % mod);
        printf("\n");
    }
    return 0;
}

Self-examination

个人训练赛结束 然后就是组队训练赛了
感觉这段时间还是不够努力 并不是特别的专心
然后呢 既然是学习 还是要好好思考 记笔记 学懂
补题的时候不能照着博客写就完事了
要会用伪代码 思路更清晰一点
再努力一点就好 坚持下去