1. 程式人生 > >EXAM-2018-8-10

EXAM-2018-8-10

prior queue names bool long 既然 its 預處理 優先

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

個人訓練賽結束 然後就是組隊訓練賽了
感覺這段時間還是不夠努力 並不是特別的專心
然後呢 既然是學習 還是要好好思考 記筆記 學懂
補題的時候不能照著博客寫就完事了
要會用偽代碼 思路更清晰一點
再努力一點就好 堅持下去


EXAM-2018-8-10