2017zstu新生賽

 

1.b^3 - a^3 = c(zy)

zy說要卡nlogn的,然而他實際給的組數只有100組,而後由於在windows下隨機的,因此給出的 c <= 100000。而後只要膽子大。。。。c++

經過打表發現,x^3-(x-1)^3 <= 1e9, x的最大值是18258面試

而後咱們用一個數組去記錄 2^3-1^3, 3^3-2^3, 4^3-3^3, ...., 18258^3-18257^3windows

對於c, 用尺取去判斷就行了數組

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int UP = 18258 + 10;
vector<ll> ss;
int c;

int main () {
    for (ll i=2; i<UP; ++i) {
        ss.emplace_back(i*i*i-(i-1)*(i-1)*(i-1));
    }
    freopen("1.in","r",stdin);
    freopen("11.out","w",stdout);
    while (~ scanf("%d", &c)) {
        ll sum = 0;
        deque<int> q;
        bool flag = false;
        for (int i=0; i<UP; ++i) {
            q.push_back(i);
            sum += ss[i];
            while (!q.empty() && sum>c) {
                sum -= ss[q.front()];
                q.pop_front();
            }
            if (sum==c) {
                flag = true;
                printf ("%d %d\n", q.front()+1, q.back()+2);
                break;
            }
        }
        if (!flag) puts("-1");
    }
    return 0;
}
View Code

 

 

2.cs的禁斷魔法(zy)

主席樹 + 二分,而後感受是全部題裏寫起來最費勁的ide

 

deep是點在樹上的深度,maxdeep(i) : 表示在i這棵子樹裏,會出現的最大deep函數

把全部點按照(deep, val)去sort,而後按照deep從小到大去建主席樹。spa

建主席樹就是按照dfs序插入到線段樹裏,而後區間維護最小值。3d

而後對於每次詢問 x c, 就二分深度,而後用主席樹check就行了code

整體複雜度:O(nlogn + Qloglog)blog

#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int M = 1e5+10;
const int logn = 22;
const int nill = 0;
typedef pair<int,int> pii;
int deep[M], maxndeep[M];
pii a[M];
int val[M];
vector<int> g[M];
int tin[M], tout[M], tim;
int n, Q;
 
void dfs (int u) {
    tin[u] = ++tim;
    maxndeep[u] = deep[u];
    for (int i=0; i<g[u].size(); ++i) {
        int v = g[u][i];
        deep[v] = deep[u]+1;
        a[v].first = a[u].first+1;
        a[v].second = v;
        dfs(v);
        maxndeep[u] = max(maxndeep[u], maxndeep[v]);
    }
    tout[u] = tim;
}
 
int rt[M], ls[M*logn], rs[M*logn], T[M*logn];
 
struct Segtree {
    int sz;
    int alloc(int u) {
        T[sz] = T[u], ls[sz] = ls[u], rs[sz] = rs[u], T[sz] = T[u];
        return sz ++;
    }
    void init() {
        rt[nill] = ls[nill] = rs[nill] = 0, T[nill] = inf;
        sz = 1;
    }
    void ins(int &o,int u,int l,int r,int x,int val) {
        o = alloc(u);
        T[o] = min(T[o], val);
        if (l==r) return;
        int mid = l+r>>1;
        if (x<=mid) ins(ls[o],ls[u],l,mid,x,val);
        else ins(rs[o],rs[u],mid+1,r,x,val);
    }
    int ask(int o,int l,int r,int pl,int pr) {
        if (pl<=l&&r<=pr) return T[o];
        int mid = l+r>>1;
        if (pl<=mid && pr>mid) return min(ask(ls[o],l,mid,pl,pr), ask(rs[o],mid+1,r,pl,pr));
        if (pl<=mid) return ask(ls[o],l,mid,pl,pr);
        return ask(rs[o],mid+1,r,pl,pr);
    }
}sgt;
 
int solve(int x,int c) {
    int l = deep[x], r = maxndeep[x], ret = -1;
    //printf ("maxndeep(%d)=%d\n", x, maxndeep[x]);
    //printf ("pl=%d,pr=%d\n", tin[x], tout[x]);
    //printf ("%d,%d:l=%d,r=%d\n", x,c,l,r);
    while (l <= r) {
        int mid = l+r>>1;
        //printf ("ask(%d)=%d\n", mid, sgt.ask(rt[mid],1,n,tin[x],tout[x]));
        if (sgt.ask(rt[mid],1,n,tin[x],tout[x]) > c) {
            ret = mid, l = mid+1;
        } else r = mid-1;
    }
    //printf ("ret=%d\n", ret);
    return ret==-1 ? 0 : ret - deep[x] + 1;
}
 
int main () {
    //freopen("2.in", "r", stdin);
    //freopen("22.out","w",stdout);
    while (~scanf("%d%d", &n,&Q)) {
        for (int i=1; i<=n; ++i) {
            g[i].clear();
            scanf ("%d", val+i);
        }
        for (int i=2, u; i<=n; ++i) {
            scanf ("%d", &u);
            g[u].push_back(i);
        }
        a[1] = make_pair(1, 1);
        deep[1] = 1;
        tim = 0;
        dfs(1);
        sort(a+1, a+1+n);
        sgt.init();
        for (int i=1,j=1; i<=maxndeep[1]; ++i) {
            rt[i] = rt[i-1];
            while(j<=n && a[j].first == i) {
                sgt.ins(rt[i],rt[i],1,n,tin[a[j].second], val[a[j].second]);
                ++j;
            }
        }
        //puts("------------------");
        int x, c;
        while (Q --) {
            scanf ("%d%d", &x,&c);
            printf ("%d\n", solve(x,c));
        }
    }
    return 0;
}
View Code

 

 

3.CS考四級(lyf)

 後綴自動機,原本想教下16級小朋友的,而後好像沒有時間了,大概留下個坑,讓他們本身填吧,hhhhh

 

首先把每一個串按照 #s1#s2#s3#....sn差到sam裏,(這裏的#指標是特殊字符而已,個人模板裏經過Inskey()函數來實現)

對於sam裏的葉子節點能夠經過len(i)數組和 #s1#s2#s3#....sn進行映射,找到對應的id

而後咱們維護sam裏的每一個節點的 (min(id), max(id))便可,若是這兩個值出如今同一個字符串s(i)裏,那麼對於當前這個節點來講,

它全部能夠接受的串都是s(i)的特徵串

由於題目要求每一個串字典序最小的,因此再dfs處理下就行了

整體複雜度:O(segma(s(i))

//注意:由於 sam 在頭部插入了一個 nill 字符(若是沒有nill,right集會少
//因此對於 parent樹 的葉子:
//若是 l(leaf) == l(fa(leaf)) + 1, 那麼說明實際上從 fa(leaf) -> leaf這條邊其實是經過走 nill 字符經過的,
//及原串其實是不會走到這個節點的。
//hdu6194
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int M = 2e5 + 10;
int n;
char s[M];
int col[M<<1];
string ans[M];
 
struct SAM {
    static const int kN = M << 1;
    static const int chN = 26;
    int fa[kN];
    int go[kN][chN];
    int l[kN];
    int o;
    int rt;
    int lst;
 
    inline int newNode(int _l) {
        for (int i=0; i<chN; ++i) {
            go[o][i] = -1;
        }
        l[o] = _l;
        return o ++;
    }
    void Init() {
        o = 0;
        rt = lst = newNode(0);
        fa[rt] = -1;
    }
    inline void InsKey() {
        int p = lst, np = newNode(l[lst]+1); lst = np;
        fa[np] = rt;
    }
    inline void Ins(int c) {
        int p = lst, np = newNode(l[lst]+1); lst = np;
        //printf ("%c:%d\n", c+'a', np);
        while (~p && go[p][c] == -1) go[p][c] = np, p = fa[p];
        if (p==-1) fa[np] = rt;
        else {
            int q = go[p][c];
            if (l[p]+1 == l[q]) fa[np] = q;
            else {
                int nq = newNode(l[p]+1);
                //printf ("%c:%d\n", c+'a', nq);
                memcpy(go[nq], go[q], sizeof(go[q]));
                fa[nq] = fa[q];
                fa[q] = fa[np] = nq;
                while (~p && go[p][c] == q) go[p][c] = nq, p = fa[p];
            }
        }
    }
 
    //topo
    int ord[kN];
    int cnt[kN];
    int right[kN];
    int in[kN];
    void topo() {
        int maxVal = 0;
        memset (cnt, 0, sizeof(cnt[0])*o);
        for (int i=0; i<o; ++i) maxVal = max(maxVal, l[i]), ++ cnt[l[i]];
        for (int i=1; i<=maxVal; ++i) cnt[i] += cnt[i-1];
        for (int i=0; i<o; ++i) ord[-- cnt[l[i]]] = i;
    }
    int cc[kN][2];
    vector<char> st;
    void dfs(int o) {
        if (o!=rt) {
            //printf ("%d:(%d,%d), ", o, cc[o][0], cc[o][1]);
            //cout << st << endl;
            if (cc[o][0] == cc[o][1] && !cnt[cc[o][0]]) {
                cnt[cc[o][0]] = 1;
                for (int i=0; i<st.size(); ++i) ans[cc[o][0]] += st[i];
                //ans[cc[o][0]] = st;
            }
        }
        for (int i=0; i<26; ++i) if (go[o][i]!=-1){
            st.push_back('a'+i);
            dfs(go[o][i]);
            st.pop_back();
        }
    }
    void solve() {
        //for (int i=1; i<o; ++i) printf ("fa(%d)=%d\n", i, fa[i]);
        topo();
        memset (cnt, 0, sizeof(cnt[0])*o);
        memset (in, 0, sizeof(in[0])*o);
        for (int i=1; i<o; ++i) ++in[fa[i]];
        for (int i=1; i<o; ++i) {
            if(!in[i]) {
                //printf ("%d:l=%d,col=%d\n", i, l[i], col[l[i]-1]);
                cc[i][0] = cc[i][1] = col[l[i]-1];
            } else {
                cc[i][0] = inf, cc[i][1] = -inf;
            }
        }
        for (int i=o-1; i>0; --i) {
            int f = fa[ord[i]];
            cc[f][0] = min(cc[f][0], cc[ord[i]][0]);
            cc[f][1] = max(cc[f][1], cc[ord[i]][1]);
        }
        st.clear();
        dfs(rt);
    }
} sam;
 
int main () {
    //freopen("3.in", "r", stdin);
    //freopen("3.out", "w", stdout);
    while (~scanf("%d", &n)) {
        sam.Init();
        int len = 0;
        for (int i=0; i<n; ++i) {
            ans[i].clear();
            sam.InsKey();
            col[len ++] = i;// ????
            scanf ("%s", s);
            for (int j=0; s[j]; ++j) {
                sam.Ins(s[j]-'a');
                col[len ++] = i;
            }
        }
        sam.solve();
        for (int i=0; i<n; ++i) {
            if (ans[i].empty()) puts("-1");
            else cout << ans[i] << endl;
        }
    }
    return 0;
}
/*
2
aba
ab
 
2
ab
ab
 
2
bd
ad
 
4
abd
bdc
ddd
abab
*/
View Code

 

 

4.這不珂學 (lyf)

莫隊+莫比烏斯容斥

 

大概高年級全部人都會求 n 個數的互質對數吧?(不會的話,請先去學這個)。

而後你會發現算貢獻的時候,其實就只和每一個數的約數有關係,因此一個個算顯然也是沒有問題的。。。而後就沒了

 

整體複雜度:O(n*sqrt(n)*60),60是由於1e4之內的數約數數量的最大值是60

 

#include<bits/stdc++.h>
using namespace std;
const int M = 1e5 + 10;
const int block = 150;
typedef long long ll;
 
vector<int> yue[M];
vector<bool> isprime;
vector<int> mu;
void sieve () {
    isprime.assign(M, true);
    isprime[0] = isprime[1] = false;
    for (int i=2; i<M/i; ++i) if (isprime[i]) {
        for (int j=i*i; j<M; j+=i) {
            isprime[j] = false;
        }
    }
    mu.assign(M, 1);
    for (int i=2; i<M; ++i) if (isprime[i]) {
        if (i<M/i) {
            for (int j=i*i; j<M; j+=i*i) mu[j] = 0;
        }
        for (int j=i; j<M; j+=i) mu[j] *= -1;
    }
    for (int i=1; i<M; ++i) {
        for (int j=i; j<M; j+=i) {
            yue[j].push_back(i);
        }
    }
}
 
int n, m;
int a[M];
int ans[M];
int cnt[M];
int l, r;
int nowAns;
 
struct Query {
    int l, r;
    int id;
    bool operator < (const Query &rhs) const {
        if (l/block == rhs.l/block) {
            return r < rhs.r;
        }
        return l < rhs.l;
    }
}qu[M];
 
void Move(int x,int tp) {
    //printf ("a(%d)=%d, tp=%d\n", x, a[x], tp);
    if (tp==1) {
        for (int i=0; i<yue[a[x]].size(); ++i) {
            int &v = yue[a[x]][i];
            //printf ("cnt(%d)=%d\n",v , cnt[v]);
            nowAns += 1ll*mu[v]*cnt[v];
            ++cnt[v];
        }
    } else {
        for (int i=0; i<yue[a[x]].size(); ++i) {
            int &v = yue[a[x]][i];
            --cnt[v];
            nowAns -= 1ll*mu[v]*cnt[v];
        }
    }
    //printf ("nowAns=%I64d\n", nowAns);
}
 
void solve() {
    sort(qu, qu+m);
    l = r = nowAns = 0;
    for (int i = 0; i < m; ++i) {
        const Query &q = qu[i];
        while (l > q.l) Move(--l, 1);
        while (r < q.r) Move(++r, 1);
        while (l < q.l) Move(l++, -1);
        while (r > q.r) Move(r--, -1);
        ans[q.id] = nowAns;
    }
}
 
int main () {
    sieve();
    //freopen("4.in", "r", stdin);
    //freopen("4.out", "w", stdout);
    while (~scanf ("%d%d", &n,&m)) {
        for (int i=1; i<=n; ++i) {
            scanf ("%d", a+i);
        }
        for (int i=0; i<m; ++i) {
            scanf ("%d%d", &qu[i].l, &qu[i].r);
            qu[i].id = i;
        }
        memset (cnt, 0, sizeof(cnt));
        solve();
        for (int i=0; i<m; ++i) {
            printf ("%d\n", ans[i]);
        }
    }
    return 0;
}
/*
4 2
15 10 6 7
1 3
2 4
*/
View Code

 

 

5. 情人節的阻擊 (lyf)

這種xjb題目區域賽常常會出

 

分紅兩類討論:

一類是貼角放,儘可能放成正方形的;

另外就是沿着短一點的邊放

 

#include<bits/stdc++.h>
using namespace std;
int n, m, x, y;

int work(int x) {
    int f = sqrt(x);
    if (f*f>=x) return 2*f;
    if (f*(f+1)>=x) return 2*f+1;
    return 2*(f+1);
}

int main () {
    //freopen("5.in", "r", stdin);
    //freopen("5.out", "w", stdout);
    while (~scanf("%d%d%d%d", &n,&m,&x,&y)) {

        if (n>m) swap(n, m);
        if (x>y) swap(x, y);
        int ans1 = 0;
        if (x/n < 1) ans1 = x + 1;
        else ans1 = (x%n>0) + n;
        printf ("%d\n", min(ans1, work(x)));
    }
    return 0;
}
/*
1 2 1 1

2 4 2 6

2 4 4 4

3 4 4 8

3 4 3 9
*/
View Code

 

 

6.男生女生配(lyf)

樹狀數組

 

靈兒當時來問了這題這麼作,感受看着對話可能更容易理解:

 

其實就是由於每一個點和它左下角的點的曼哈頓距離能夠經過:x1+y1 - (xi+yi)來求

整體複雜度:O((n+m)*log(200000))

 

#include<bits/stdc++.h>
using namespace std;
const int M = 200000+10;
const int DJ = 200000+1;
const int inf = 0x3f3f3f3f;
int n, m;
struct Node {
    int x, y, tp, id;
}a[M<<1];
int ans[M];
 
int c[M];
void init() {
    memset(c, -1, sizeof(c[0])*M);
}
void ins(int x,int v) {
    for (int i=x; i<M; i+=i&-i) c[i] = max(c[i], v);
}
int ask(int x) {
    int ret = -1;
    for (int i=x; i>0; i-=i&-i) ret = max(ret, c[i]);
    return ret;
}
void change() {
    for (int i=0; i<n+m; ++i) {
        int tmp = a[i].x;
        a[i].x = DJ-a[i].y;
        a[i].y = tmp;
    }
}
 
bool cmp(const Node &a,const Node &b) {
    if (a.x==b.x) {
        if (a.y==b.y) return a.tp<b.tp;
        return a.y<b.y;
    }
    return a.x<b.x;
}
void update() {
    init();
    sort(a, a+n+m, cmp);
    for (int i=0; i<n+m; ++i) {
        if (a[i].tp==0) {
            ins(a[i].y, a[i].x+a[i].y);
        } else {
            int ret = ask(a[i].y);
            if (ret!=-1) ans[a[i].id] = min(ans[a[i].id], a[i].x+a[i].y-ret);
        }
    }
}
 
int main () {
    //freopen("6.in", "r", stdin);
    //freopen("6.out", "w", stdout);
    while (~scanf("%d", &n)) {
        for (int i=0; i<n; ++i) {
            scanf ("%d%d", &a[i].x,&a[i].y);
            a[i].tp = 0;
        }
        scanf("%d", &m);
        for (int i=0; i<m; ++i) {
            scanf ("%d%d", &a[i+n].x,&a[i+n].y);
            a[i+n].tp = 1;
            a[i+n].id = i;
        }
        memset(ans, inf, sizeof(ans[0])*m);
        for (int i=0; i<4; ++i) {
            if (i) change();
            update();
        }
        for (int i=0; i<m; ++i) {
            printf ("%d\n", ans[i]);
        }
        //printf ("%d\n", ans[0]);
    }
    return 0;
}
/*
2
1 1
3 3
1
2 4
*/
View Code

 

 

7.光梯(Noland)

有題意可知,對最後一個點形成影響的點是它前面k個點點,若是知道他前面k個點的指望,在求出每一個點走到最後一個點走到這個點的機率,那麼就能夠求出最後一個點的指望,
如何求出前k個點走到最後一個點所佔的比率,假設已知前n-1個點的指望,當只能走到下標爲n-k的點時,將會有1/k的部分走到最後一個點,當只能走到下標爲n-k+1的點時,還
剩餘總體的(k-1)/k,而後又1/(k-1)的機率走到最後一個點,而後能夠知道每一個點走到最後一個點的機率都是1/k,全部就是前k個點的和除以k,由於這題n和q比較大,可是k比
較小,能夠先打表獲得全部的值,而後對於詢問直接輸出便可。

 

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
const int M = 107;
double dp[M][N];
void  init(){
    memset(dp,0,sizeof(dp));
    for(int i = 1;i < M;i ++){
        double sum = 0;
        for(int j = 1;j < N;j ++){
            sum += dp[i][j-1];
            int res = min(i,j);
            if(j > i){
                sum -= dp[i][j-min(i,j)-1];
            }
            dp[i][j] = sum / min(i,j)+1;
        }
    }
}

int main(){
    init();
    freopen("7.in","r",stdin);
    freopen("7.out","w",stdout);
    int n,k;
    while(scanf("%d %d",&n,&k)==2){
        printf("%.3f\n",dp[k][n]);
    }
    return 0;
}
View Code

 

 

8.magic number(xufei)

看着題目,其實很容易發現 小於等於 S 的都是magic, 而後對於大於 S的,最多隻要往上跑 9*9 暴力判就行了,由於1e9裏內全部位的和最大值撐死也就 81

 

9.科學計數法

比賽的時候,我一直在想,爲啥你們都懟着A,不作這題。。。。。

 

10.我好方

我連公式都給了啊!!!爲何還有wa的!!!!

 

11.不要方

這道題實際上是個面試題

咱們把矩形的四條邊稱做(上,下,左,右),

而後對於(上1,上2)選靠下邊的線,對於(下1,下2)選靠上邊的線

對於(左1,左2)選靠右的線,對於(右1,右2)選靠左的線

而後只要這新的四條線,有交集,那個交集的面積就是答案了。

(PS:其實由於數據很小,你暴力模擬染色技術也能過)

 

12.丟手絹(baobao)

你把正n邊形,和正n-1邊形隨便找個點拆開來,鋪成一條線,而後很容易發現規律。。。。

而後比賽的時候有人用 O(1e9)過了,好像仍是咱們學校的小夥子,hhhh

具體證實以下:

假設如今有兩種點,第一種點是有n個點的,第二種有n-1個點的,假設這兩種點的第一個點是重合的,很容易證第2種點的第i個在第1種點的第i個和第i+1之間,在第二種點中,當i小於(n+1)/2時,距離它最近的第一種點事第i個點,當i大於(n+1)/2時,距離它最近的點事第i+1個點,當i等於(n+1)/2時,它距離第i個和第i+1個點的距離是相同的,能夠發現每一個點離得最近的點沒有重複的,全部每一個點移動到它最近的點就行了,計算距離的時候,當i小於(n+1)/2時,距離他最近的點的距離是(i-1)/(n*(n-1)),這就是一個等差數列,大於(n+1)/2的點也同樣,而後等差數列求和就行了。

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps = 1e-9;
ll n;
 
int main () {
    while (~ scanf("%lld", &n)) {
        if (n<=2) {
            puts("0");
            continue;
        }
        double x = 1.0/n, y = 1.0/(n-1);
        ll f = (n-1)/2;
        double ans = (1+f)*f/2.0*(y-x)*2;
        //cout << ans << endl;
        ans -=  0.5 - 1.0/n*(n/2);
        printf ("%.0f\n", ans*1000+eps);
    }
    return 0;
}
View Code
相關文章
相關標籤/搜索