1. 程式人生 > >2017廣西邀請賽補題

2017廣西邀請賽補題

2017廣西邀請賽模擬

傳送門

HDU 6182 A Math Problem

數學題。。我和老譚都做過,就交給學弟去做。實際上回憶一下計組的知識,1616=264,longlong就爆了。所以這題答案最大16,預處理15以內的數,暴力判斷就好。

#include<bits\stdc++.h>
#define M(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MAXN=100007
; typedef long long LL; unsigned long long mp[17]; void init() { for(unsigned long long i=1;i<=16;i++) { unsigned long long ans=1; for(int j=1;j<=i;j++) { ans*=i; } mp[i]=ans; } } int main() { init(); //for(int i=1;i<=16;i++)
// printf("%d:%llu\n", i, mp[i]); int ans=0; unsigned long long n; while(cin>>n) { for(int i=1;i<=15;i++) { if(mp[i]<=n) ans=i; else break; } cout<<ans<<endl; } return 0; }

學弟寫A時我在弄C,dfs四元環,簡單寫了一發MLE。。不知那裡寫錯了了。。學弟找到水題E,求除了某個數以外其他數的and or xor。xor很好辦,整體異或在異或被排除的數即可。and和or,資料1e5,暴力統計每一位的1個數,減去特定數字每一位的1,再判斷。and某位是1的情況是1的個數==n-1,or某位是1的情況是1的個數>0。sb題WA兩發。。

HDU 6186 CS Course

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<string>
using namespace std;
const int MAXN=100007;
int sum[35];
int a[MAXN];
int main()
{
    int n, q;
    while(scanf("%d%d", &n, &q)==2)
    {
        memset(sum, 0, sizeof(sum));
        int xorval=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d", &a[i]);
            xorval^=a[i];
            for(int j=0;j<30;j++)
            {
                if((1<<j)&a[i])
                    sum[j]++;
            }
        }
        for(int i=1;i<=q;i++)
        {
            int kk;scanf("%d", &kk);
            int andval=0, orval=0;
            for(int j=0;j<30;j++)
            {
                if((1<<j)&a[kk])
                {
                    if(sum[j]>1)
                        orval|=(1<<j);
                    if(sum[j]==n)
                        andval|=(1<<j);
                }
                else
                {
                    if(sum[j]>0)
                        orval|=(1<<j);
                    if(sum[j]==n-1)
                        andval|=(1<<j);
                }
            }
            printf("%d %d %d\n", andval, orval, xorval^a[kk]);
        }
    }
    return 0;
}

老譚發現數學題後就一直在搞,D題,wa一發後過了。我完全沒看。。。

HDU 6185 Covering

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 6
#define LL long long
using namespace std;
const LL m=1000000007;

struct Matrix
{
    LL  a[MAXN][MAXN];
    int r, c;
};
Matrix ori, res;
LL  F[5];//F矩陣
LL  Ans[5];//結果矩陣
void init()
{
    //構造矩陣
    ori.r = ori.c = 4;
    memset(ori.a, 0, sizeof(ori.a));
    ori.a[0][0] = ori.a[0][2] = 1;
    ori.a[0][3] =  -1;
    ori.a[0][1] =   5;
    ori.a[1][0] = ori.a[2][1] = ori.a[3][2] = 1;
    //構造單位矩陣
    res.r = res.c = 4;
    memset(res.a, 0, sizeof(res.a));
    res.a[0][0] = res.a[1][1] = res.a[2][2] = res.a[3][3] = 1;
    //構造F矩陣
    F[0] = 11, F[1] = 5, F[2] = 1, F[3] = 1;
}
Matrix muitl(Matrix x, Matrix y)
{
    Matrix z;
    memset(z.a, 0, sizeof(z.a));
    z.r = x.r; z.c = y.c;
    for(int i = 0; i < x.r; i++)
    {
        for(int k = 0; k < x.c; k++)
        {
            if(x.a[i][k] == 0) continue;
            for(int j = 0; j < y.c; j++)
                z.a[i][j] = (z.a[i][j] + (x.a[i][k] * y.a[k][j]) % m +m) % m;
        }
    }
    return z;
}

void Matrix(LL n)
{
    while(n)
    {
        if(n & 1)
            res = muitl(ori, res);
        ori = muitl(ori, ori);
        n >>= 1;
    }
}

void solve(LL n)
{
    Matrix(n);//矩陣的n次冪 對m取餘
    memset(Ans, 0, sizeof(Ans));
    for(int i = 0; i < res.r; i++)
    {
        for(int k = 0; k < res.c; k++)
            Ans[i] = (Ans[i] + res.a[i][k] * F[k]%m +m ) % m;
    }
    printf("%lld\n", (Ans[0]+m)%m);
}

int main()
{
    LL  L;
    while(scanf("%lld", &L) != EOF)
    {
        Ans[0] = 1, Ans[1] = 1, Ans[2] = 5, Ans[3] = 11;
        if(L <= 3)
        {
            printf("%lld\n", Ans[L]);
            continue;
        }
        init();//構造矩陣
        solve(L-3);
    }
    return 0;
}

我做完E後就一直和學弟打撲克,瘋狂貪心,不過一直沒太好的策略,一開始想的複雜了,情況太多了。期間老譚又過了F題。

HDU 6187 Destroy Walls

#include <bits/stdc++.h>

using namespace std;
const int maxn=100007;
const int maxm=2000*1007;

struct Edge
{
    int u,v,dist;
    Edge(){}
    Edge(int u,int v,int d):u(u),v(v),dist(d){}
    bool operator<(const Edge &rhs)const
    {
        return dist >rhs.dist;//按邊長從大到小排序
    }
};

struct Kruskal
{
    int n,m;
    Edge edges[maxm];
    int fa[maxn];
    int findset(int x){return fa[x]==-1? x:fa[x]=findset(fa[x]); }

    void init(int n)
    {
        this->n=n;
        m=0;
        memset(fa,-1,sizeof(fa));
    }

    void AddEdge(int u,int v,int dist)
    {
        edges[m++]=Edge(u,v,dist);
    }

    pair<int,int> kruskal()
    {
        pair<int,int> ans;
        sort(edges,edges+m);

        for(int i=0;i<m;i++)
        {
            int u=edges[i].u, v=edges[i].v;
            if(findset(u) != findset(v))
            {
                fa[findset(u)] = findset(v);
                ans.first++;
                ans.second+=edges[i].dist;
            }
        }
        return ans;
    }
}KK;


int main() {
    int n,m;
    while(scanf("%d %d",&n,&m)!=EOF){
        int u,v,w;
        int sum=0;
        KK.init(n);
        for(int i=1;i<=n;i++)
            scanf("%d %d",&u,&v);

        for(int i=1;i<=m;i++)
            scanf("%d %d %d",&u,&v,&w),
            KK.AddEdge(u,v,w),
            sum+=w;

        pair<int,int>ans = KK.kruskal();
        printf("%d %d\n",m-ans.first,sum-ans.second);
    }    
    return 0;
}

G我們終於有了個比較簡單的思路,當前牌i先全組對子,要是沒剩的就繼續下一張,要是剩一張就判斷i+1的個數是不是奇數,要是是奇數就判斷i+2有沒有,有就組個順子。正確性:假如i+1是偶數,那麼不要拆對子,無論i+2奇偶都不會變壞;i+1奇數,就可以拿出多與的一張,這樣即使i+2是偶數,也就是吧一個對子(i+2的)換成了順子,也不會變壞。

HDU 6188 Duizi and Shunzi

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<string>
using namespace std;
const int MAXN=100007;
int cd[MAXN];
int main()
{
    int n;
    while(scanf("%d", &n)==1)
    {
        int sum=0;
        memset(cd, 0, sizeof(cd));
        for(int i=1;i<=n;i++)
        {
            int tmp;scanf("%d", &tmp);
            cd[tmp]++;
        }
        for(int i=1;i<MAXN-5;i++)
        {
            sum+=(cd[i]/2);
            cd[i]%=2;
            if(cd[i]>=1&&cd[i+1]%2==1&&cd[i+2]>=1)
            {
                sum++;
                cd[i]--;
                cd[i+1]--;
                cd[i+2]--;
            }
        }
        printf("%d\n", sum);
    }
    return 0;
}

這時已經過去2小時,可做題還有JBC(H?)。BJ是資料結構,C是個搜尋計數,H不知道是什麼。
我和學弟討論一下J,異或可以用字典樹處理,他覺得是可持久化字典樹,不過不知道怎麼寫,我就打算寫啟發式合併。正打算寫(感覺也寫不出來),旁邊隊藍名巨佬告訴我他打廣西的網路同步賽用dsu過的,我瞬間興奮,苦學一週的dsu不能浪費啊。直接上dsu+字典樹。
這裡說一嘴,dsu的複雜度和編碼難度都比較不錯,不過一般需要一種輔助資料結構去配合,就是看能不能想到這種輔助結構。解決樹上無修改問題基本都能用。

HDU 6191 Query on A Tree

第一發T是因為沒清vector,第二發re是因為字典樹的節點個數n沒清零。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<string>
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=100007;
vector<int> G[MAXN];
int val[MAXN];
struct Query
{
    int id;
    int v;
    int ne;
}q[MAXN];
int qhead[MAXN];
int qnum=0;
int res[MAXN];
const int bit=30;

struct Trie
{
    int s;
    int ch[2];
    Trie() { s=ch[0]=ch[1]=0; }
}trie[MAXN*bit];
int sz=1;
void build() { M(trie, 0);sz=1; }
void insert(int rt, int lev, int num)
{
    if(lev==-1) { trie[rt].s=1;return; }
    int k=(num&(1<<lev))>>lev;
    if(!trie[rt].ch[k]) trie[rt].ch[k]=++sz;
    insert(trie[rt].ch[k], lev-1, num);
    trie[rt].s=trie[trie[rt].ch[0]].s|trie[trie[rt].ch[1]].s;
}
void remove(int rt, int lev, int num)
{
    if(lev==-1) { trie[rt].s=0;return; }
    int k=(num&(1<<lev))>>lev;

    remove(trie[rt].ch[k], lev-1, num);
    trie[rt].s=trie[trie[rt].ch[0]].s|trie[trie[rt].ch[1]].s;
}
int query(int rt, int lev, int val)
{
    if(lev==-1) return 0;
    if((val&(1<<lev))>0)
    {
        if(trie[trie[rt].ch[0]].s==1)
        {
            return query(trie[rt].ch[0], lev-1, val);
        }
        else
        {
            return query(trie[rt].ch[1], lev-1, val)+(1<<lev);
        }
    }
    else
    {
        if(trie[trie[rt].ch[1]].s==1)
        {
            return query(trie[rt].ch[1], lev-1, val)+(1<<lev);
        }
        else
        {
            return query(trie[rt].ch[0], lev-1, val);

        }
    }
}


int hson[MAXN], sonsz[MAXN];
void dfs1(int u, int fa)
{
    sonsz[u]=1;
    for(int i=0;i<G[u].size();i++)
    {
        if(G[u][i]!=fa)
        {
            dfs1(G[u][i], u);
            if(hson[u]==-1)
            {
                hson[u]=G[u][i];
            }
            else if(sonsz[hson[u]]<sonsz[G[u][i]])
            {
                hson[u]=G[u][i];
            }
            sonsz[u]+=sonsz[G[u][i]];
        }
    }
}
int hs;
void add(int x)
{
    insert(1, bit, val[x]);
    for(int i=0;i<G[x].size();i++)
        if(G[x][i]!=hs)
            add(G[x][i]);
}

void del(int x)
{
    remove(1, bit, val[x]);
    for(int i=0;i<G[x].size();i++)
        if(G[x][i]!=hs)
            del(G[x][i]);
}

void dfs2(int u, int fa, int kp)
{
    for(int i=0;i<G[u].size();i++)
        if(G[u][i]!=hson[u])
        {
            dfs2(G[u][i], u, 0);
        }
    if(hson[u]) dfs2(hson[u], u, 1), hs=hson[u];
    add(u);hs=0;
    for(int i=qhead[u];~i;i=q[i].ne)
    {
        res[q[i].id]=query(1, bit, q[i].v);
        res[q[i].id]^=q[i].v;
    }
    if(!kp)
        del(u);
}

int main()
{
    int n, qq;
    while(scanf("%d%d", &n, &qq)==2)
    {
        for(int i=1;i<=n;i++)G[i].clear();
        for(int i=1;i<=n;i++)
        {
            scanf("%d", &val[i]);
        }
        for(int i=2;i<=n;i++)
        {
            int k;scanf("%d", &k);
            G[k].push_back(i);
        }
        memset(qhead, -1, sizeof(qhead));
        qnum=0;
        for(int i=1;i<=qq;i++)
        {
            int x, v;
            scanf("%d%d", &x, &v);
            q[++qnum].v=v;
            q[qnum].ne=qhead[x];
            qhead[x]=qnum;
            q[qnum].id=i;
        }

        M(hson, 0);
        build();
        dfs1(1, 0);
        dfs2(1, 0, 0);
        for(int i=1;i<=qq;i++)
        {
            printf("%d\n", res[i]);
        }
    }
    return 0;
}

我寫J時學弟在搞數星星,不過賽後才搞出來。我寫過J後就搞B的資料結構,二維的。不過處理一下可以變成一維的。先是C的程式碼:

HDU 6184 Counting Stars

#include<bits\stdc++.h>
using namespace std;
vector<int>G[100005];
set<long long>s;
int n, m, cnt, fa[100005];
bool vis[100005];
long long ans;
long long getint()
{
    long long ret=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while('0'<=ch&&ch<='9') { ret=ret*10+ch-'0';ch=getchar(); }
    return ret;
}
int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        memset(vis, 0, sizeof(vis));
        memset(fa, 0, sizeof(fa));
        s.clear();
        for(int i=1;i<=n;i++)G[i].clear();
        for(int i=1;i<=m;i++)
        {
            long long x=getint();
            long long y=getint();
            G[x].push_back(y);
            s.insert((long long)n*x+y);
            s.insert((long long)n*y+x);
            G[y].push_back(x);
        }
        long long ans=0;

        for(int i=1;i<=n;i++)
        {
            vis[i]=1;
            int x=i;
            for(int j=0;j<G[x].size();j++)fa[G[x][j]]=x;
            for(int j=0;j<G[x].size();j++)
            {
                int y=G[x][j];
                if(vis[y])continue;
                long long sum=0;

                if(G[y].size()<=(int)sqrt(m))
                {
                    for(int k=0;k<G[y].size();k++)
                    {
                        int z=G[y][k];
                        if(fa[z]==x)sum++;
                    }
                }
                else
                {
                    for(int k=0;k<G[x].size();k++)
                    {
                        int z=G[x][k];
                        if(s.find((long long)z*n+y)!=s.end())sum++;

                    }
                }
                ans+=(sum-1)*sum/2;
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}