2019.11.07考試解題報告

總結

指望得分:\(50 + 20 + 0 = 70\)
實際得分:\(50 + 5 + 0 = 55\)node

大神\(zhx\):考試要先打暴力.ios

因而我困在\(T2\)\(20\)分暴力中沒法自拔。。調\(T2\)暴力花了一個小時……其實吧。。我想寫\(T3\),然而連怎麼建這棵樹都不會,因此就肝\(T2\)\(20\)分一直到死。。\(T1\)是個沙比題,人均\(100\)分,這場考試人均\(100+\),我就是倒着數的那個。。內心盡是失落,又實在不會這些題。。沒救了git


思路&&代碼

T1

\(50\)分:spa

直接\(n^2\)暴力找度爲\(1\)的點,每次找到就將這個點和它連邊的點度都減\(1\),而後把答案存下來最後輸出(代碼中的\(sub1\)debug

另外的\(10\)分:code

由於保證了\(u==1\),因此咱們能夠直接輸出\(n-2\)\(1\)隊列

\(100\)分:get

考慮用一個優先隊列,把度爲\(1\)的結點的編號放入隊列中,保證每次取出的編號最小,而後直接枚舉這些點的連邊,讓連邊的點度數\(--\),若是此時度數變爲\(1\)則入隊,若是此時度數大於等於\(1\)則輸出這個點,這樣就作完了string

#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;

inline int read() {
    char c = getchar(); int x = 0, f = 1;
    for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
    return x * f;
}

int n, m;
struct node { int to, nxt; } e[A];
bool flag = 1;
int cnt = 0, tot = 0, head[A], du[A], ans[A], vis[A];
priority_queue <int, vector<int>, greater<int> > Q;

inline void add(int from, int to) {
    e[++cnt].to = to;
    e[cnt].nxt = head[from];
    head[from] = cnt;
}

namespace sub1 {
    void solve(int id) {
        vis[id] = 1;
        int to = e[head[id]].to;
        if(!vis[to]) {
            du[to]--; if(du[to] == 0) vis[to] = 1;
            ans[++tot] = to; head[id] = e[head[id]].nxt;
        } else {
            while(vis[to] && to != 0) {
                head[id] = e[head[id]].nxt;
                to = e[head[id]].to;
            }
            ans[++tot] = to; if(du[to] == 0) vis[to] = 1;
            du[to]--; head[id] = e[head[id]].nxt;
        }
        return;
    }
    void Main() {
        vis[0] = 1;
        for(int i = 1; i <= n - 2; i++)
            for(int j = 1; j <= n; j++)
                if(du[j] == 1) {
                    du[j]--;
                    solve(j);
                    break;
                }
        for(int i = 1; i <= tot; i++) cout << ans[i] << " ";
        return;
    }
}

int main() {
    freopen("prufer.in", "r", stdin);
    freopen("prufer.out", "w", stdout);
    n = read();
    for(int i = 1, u, v; i < n; i++) {
        u = read(), v = read();
        add(u, v), add(v, u);
        if(u != 1) flag = 0;
        du[u]++, du[v]++;
    }
    
    if(n <= 3000) return sub1::Main(), 0;

    if(flag) {
        cout << 1;
        for(int i = 2; i <= n - 2; i++) cout << " 1";
        puts("");
        return 0;
    }   
    
    for(int i = 1; i <= n; i++) if(du[i] == 1) Q.push(i);
    for(int i = 1; i <= n; i++) {
        int u = Q.top(); Q.pop();
        for(int j = head[u]; j; j = e[j].nxt) {
            int to = e[j].to;
            du[to]--;
            if(du[to] == 1) Q.push(to);
            if(du[to] >= 1) cout << to << " ";
        }
    }
    puts("");
    return 0;
}
/*
6
1 3
1 5
3 2
3 6
5 4

3 5 1 3
*/

T2

\(20\)分:it

暴搜,只能從左往右搜,因此記錄一下上次用的是哪個,此次枚舉直接從上次用的下一個開始枚舉,保證從左往右

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;

inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
    return x * f;
}

int n, m, ans, vis[A], a[A];
char s[A];
int c[4000][4000];

void dfs(int cnt, int last) {
    if(cnt > n + 1) return;
    if((cnt - 1) % 2 == 0 && cnt - 1 != 0) {
        int now = cnt - 1;
        int zuo = 0, you = 0, cao = 0;
        for(int i = 1; i <= now / 2; i++) {
            if(a[i] == 2) {
                cao = 1;
                break;
            }
            if(a[i] == 1) zuo++;
        }
        for(int i = now / 2 + 1; i <= now; i++) {
            if(a[i] == 1) {
                cao = 1;
                break;
            }
            if(a[i] == 2) you++;
        }
        if(!cao && zuo == you && zuo + you == now) ans++;
    }
    for(int i = last + 1; i <= n; i++) {
        if(!vis[i]) {
            vis[i] = 1;
            a[cnt] = (s[i] == '(' ? 1: 2);
            dfs(cnt + 1, i);
            vis[i] = 0;
        }
    }
}

signed main() {
    freopen("beauty.in", "r", stdin);
    freopen("beauty.out", "w", stdout);
    scanf("%s", s + 1);
    n = strlen(s + 1);
    if(n <= 20) {
        dfs(1, 0);
        cout << ans % mod << '\n';
        return 0;
    }
    return 0;
}

\(50\)分:

考慮每一個左括號,不包括他的,左邊有多少個左括號,右邊有多少個右括號,就能夠得出,對於每個左括號的位置,都有:(\(x\)是指左邊不包括這個左括號有多少個左括號,\(y\)是右邊有多少個右括號)

\[\sum_{i = 0}^{x} C(x, i) * C(y, i + 1)\]

而後就有\(50\)

\(100\)分:

考慮直接換一種想法,咱們枚舉包括這個位置的左括號的,左邊有多少個左括號,右邊有多少個右括號,這個位置必須選,那麼就能得出

\[\sum_{i = 1}^{x} C(x, i) * C(y, i)\]

可是這樣就會把不選這個位置的狀況算上,因此還要減去

\[\sum_{i = 1}^{x} C(x - 1, i) * C(y, i)\]

就得出了
\[\sum_{i = 1}^{x} C(x, i) * C(y, i) - \sum_{i = 1}^{x} C(x - 1, i) * C(y, i) \]

有一個輔助式子

\[\sum_{i = 0}^{x} C(x, i) * C(y, i) = C(x + y, x)\]

因此上面的式子就能寫成

\[(C(x + y, x) - 1 )- ( C(x + y - 1, x - 1) - 1)\]

就等於

\[C(x + y, x) - C(x + y - 1, x - 1) \]

對於每一個左括號的位置,咱們都這樣計算一遍,而後就作完了

時間複雜度\(O(n)\)

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;

inline int read() {
    char c = getchar(); int x = 0, f = 1;
    for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
    return x * f;
}

int n, m, a[A], b[A], fac[A], inv[A], ans; //a[i]左邊的左括號個數,b[i]右邊的右括號個數 
char s[A];

int power(int a, int b, int res = 1) {
    while(b) {
        if(b & 1) res = res * a % mod;
        a = a * a % mod; b >>= 1;
    } return res;
} 

void prepare(int n) {
    fac[0] = 1;
    for(int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % mod;
    inv[n] = power(fac[n], mod - 2);
    for(int i = n - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % mod; 
    return;
}

int C(int n, int m) {
    if(n < m) return 0;
    return fac[n] % mod * inv[n - m] % mod * inv[m] % mod;
}

signed main() {
    scanf("%s", s + 1);
    n = strlen(s + 1);
    prepare(n * 2);
    for(int i = n; i >= 1; i--)
        if(s[i] == ')') b[i] = b[i + 1] + 1;
        else b[i] = b[i + 1];
    for(int i = 1; i <= n; i++) {
        if(s[i] == '(') a[i] = a[i - 1] + 1;
        else a[i] = a[i - 1]; 
    }
    for(int i = 1; i <= n; i++) {
        if(s[i] == ')') continue;
        int x = a[i], y = b[i];
        ans += C(x + y, x) - C(x + y - 1, x - 1) , ans %= mod;
    }
    ans = (ans % mod + mod) % mod;
    cout << ans << '\n';
    return 0;
}

T3

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
//var
int n,m;
//Trie
struct Tree {
    int ch[26];
    int fail;
} T[400010];
int tot;
int pos[400010];//index->node
void insert(char* st,int num) {
    int now=0,len=strlen(st);
    for(int i=0; i<len; i++) {
        if(!T[now].ch[st[i]-'a'])
            T[now].ch[st[i]-'a']=++tot;
        now=T[now].ch[st[i]-'a'];
    }
    pos[num]=now;
    return ;
}
//fail-tree
vector<int>son[400010];
//AC Automaton
queue<int>q;
void bfs() {
    for(int i=0; i<26; i++)
        if(T[0].ch[i]) {
            q.push(T[0].ch[i]);
            T[T[0].ch[i]].fail=0;
        }
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        son[T[u].fail].push_back(u);
        for(int i=0; i<26; i++)
            if(T[u].ch[i]) {
                T[T[u].ch[i]].fail=T[T[u].fail].ch[i];
                q.push(T[u].ch[i]);
            } else T[u].ch[i]=T[T[u].fail].ch[i];
    }
    return ;
}
//get dfn
int dfn[400010],to[400010],now;
//vector<char>Vec;
void dfs(int u) {
    dfn[u]=++now;
    for(int i=0; i<son[u].size(); i++)
        dfs(son[u][i]);
    to[u]=now;
    return ;
}
/*
//for debug
void _dfs(int u)
{
    printf("%d: str=",u);
    for(int i=0;i<Vec.size();i++)
        printf("%c",Vec[i]);
    printf("\n");
    for(int i=0;i<26;i++)
        if(T[u].ch[i]){
            Vec.push_back(i+'a');
            _dfs(T[u].ch[i]);
            Vec.pop_back();
        }
    return ;
}*/
//Fenwick
int c[400010];
int lowbit(int x) {
    return x&(-x);
}
void add(int x,int y) {
    for(; x<=tot+1; x+=lowbit(x))
        c[x]+=y;
    return ;
}
int query(int x) {
    int ans=0;
    for(; x; x-=lowbit(x))
        ans+=c[x];
    return ans;
}
//Song-Tree
vector<pair<int,char> >S[400010];
//queries
vector<int>qnum[400010];
//answers
int ans[400010];
//REAL-DFS
void DFS(int u,int state) {
    add(dfn[state],1);
    for(int i=0; i<qnum[u].size(); i++) {
        int v=qnum[u][i];
        ans[v]=query(to[pos[v]])-query(dfn[pos[v]]-1);
    }
    for(int i=0; i<S[u].size(); i++) {
        int v=S[u][i].first;
        int C=S[u][i].second-'a';
        DFS(v,T[state].ch[C]);
    }
    add(dfn[state],-1);
    return ;
}
char str[400010];
int main() {
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
    scanf("%d",&n);
    for(int i=1; i<=n; i++) {
        int op,fa;
        scanf("%d",&op);
        if(op==1)fa=0;
        else scanf("%d",&fa);
        scanf("%s",str);
        S[fa].push_back(make_pair(i,str[0]));
    }
    scanf("%d",&m);
    for(int i=1; i<=m; i++) {
        int u;
        scanf("%d",&u);
        scanf("%s",str);
        insert(str,i);
        qnum[u].push_back(i);
    }
//  _dfs(0);
    bfs();
    dfs(0);
    DFS(0,0);
//  for(int i=1;i<=tot;i++)
//      printf("fail[%d]=%d\n",i,T[i].fail);
    for(int i=1; i<=m; i++)
        printf("%d\n",ans[i]);
//  for(int i=1;i<=m;i++)
//      printf("%d ",pos[i]);
//  printf("\n");
    return 0;
}
相關文章
相關標籤/搜索