zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校训练营(第九场)


    A. The power of Fibonacci

    正解是这样子的:

    这个题目是某次翻Wikipedia的时候想到的
    •https://en.wikipedia.org/wiki/Fibonomial_coefficient
    •F[i]–F[i-1]–F[i-2]=0
    •F[i]^2–2F[i-1]^2–2F[i-2]^2+F[i-3]=0
    •F[i]^3–3F[i-1]^3–6F[i-2]^3+3F[i-3]+F[i-4]=0
    •可以推广吗?可以的,就是FibonomialCoefficient
    •通过简单的分析可以得到递推
    •因为m的范围是1000,需要结合多项式取模

    然而斐波那契数列模一个数是有循环的,找找循环节就完事了。

    CODE

    这是一份AC代码

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 10000005;
    const int md[2] = { 512, 1953125 };
    int f[MAXN], ans[2], n, m;
    inline int qpow(int a, int b, int c) {
        int re = 1;
        while(b) {
            if(b&1) re = 1ll * re * a % c;
            a = 1ll * a * a % c; b >>= 1;
        }
        return re;
    }
    int main () {
        cin>>n>>m;
        for(int k = 0, j; k < 2; ++k) {
            f[0] = 0; f[1] = 1;
            for(j = 2; ; ++j) {
                f[j] = (f[j-1] + f[j-2]) % md[k];
                if(f[j] == 0 && f[j-1] == 1) break; //1 = f[j+1] = f[j-1] + f[j](=0) = f[j-1]
            }
            for(int i = 0; i < j; ++i) {
                int tim = n/j;
                if(n%j >= i) ++tim;
                ans[k] = (ans[k] + 1ll * qpow(f[i], m, md[0]*md[1]) * tim % md[k]) % md[k];
            }
        }
        while(ans[1] % md[0] != ans[0]) ans[1] += md[1];
        cout<<ans[1]<<endl;
    }
    

    然后我们把 qpow(f[i], m, md[0]*md[1]) 改成 qpow(f[i], m, md[k]) 它T了。

    实际上是因为 md[0]*md[1] 是const int,快;而 md[k] 非也。

    所以你把k=0和k=1分开写,分别写成qpow(f[i], m, md[0]) 和 qpow(f[i], m, md[1])也是能过的。


    B.Quadratic equation

    正解是这样子的:

    •这个题目是某次翻Wikipedia的时候想到的
    •https://en.wikipedia.org/wiki/Quadratic_residue
    •解二次方程,核心在于求二次剩余(求平方根)
    •如果p%4=3,x^2%p=a
    •那么x=±pow(a,(p+1)/4,p)
    •然后就和一般的方程一样解就可以了
    •判断是否有解用
    •https://en.wikipedia.org/wiki/Euler%27s_criterion

    核心确实是求二次剩余。正解中用到了p%4=3的性质。

    而我用到了p有原根的性质,转为指标然后BSGS。

    实际上的任意模数二次剩余很麻烦的。。戳这里

    myCODE

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int mod = 1e9 + 7;
    int T, c, b;
    inline int qpow(int a, int b) {
        int re = 1;
        while(b) {
            if(b&1) re = 1ll * re * a % mod;
            a = 1ll * a * a % mod; b >>= 1;
        }
        return re;
    }
    map<int, int>myhash;
    inline int BSGS(int a, int b) {
        myhash.clear(); int m = int(sqrt(mod) + 1);
        int base = b;
        for(int i = 0; i < m; ++i) {
            myhash[base] = i;
            base = 1ll * base * a % mod;
        }
        base = qpow(a, m); int tmp = 1;
        for(int i = 1; i <= m+1; ++i) {
            tmp = 1ll * tmp * base % mod;
            if(myhash.count(tmp))
                return i*m - myhash[tmp];
        }
        return -1;
    }
    inline int mysqrt(int x) {
        if(!x) return 0;
        int I = BSGS(5, x);
        if(I&1) return -1;
        return qpow(5, I/2);
    }
    int main(){
        scanf("%d", &T);
        while(T-->0) {
            scanf("%d%d", &b, &c);
            int A = (1ll * b * b % mod - 4ll * c % mod) % mod;
            int B = mysqrt((A + mod) % mod);
            if(B == -1) { puts("-1 -1"); continue; }
            int y = 1ll * (b + B) * qpow(2, mod-2) % mod;
            int x = (y - B + mod) % mod;
            if(x > y) swap(x, y);
            printf("%d %d
    ", x, y);
        }
    }
    

    D.Knapsack Cryptosystem

    水题,分两半暴力。

    CODE

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    int n;
    LL s, a[40];
    map<LL,int>tmp;
    int main(){
        scanf("%d%lld", &n, &s);
        for(int i = 0; i < n; ++i)
            scanf("%lld", &a[i]);
        int m = n/2;
        for(int st = 0; st < (1<<m); ++st) {
            LL sum = 0;
            for(int i = 0; i < m; ++i)
                if(st&(1<<i)) sum += a[i];
            tmp[sum] = st;
        }
        tmp[0] = 0;
        for(int st = 0; st < (1<<(n-m)); ++st) {
            LL sum = 0;
            for(int i = m; i < n; ++i)
                if(st&(1<<(i-m))) sum += a[i];
            if(tmp.count(s-sum)) {
                int t = tmp[s-sum];
                for(int i = 0; i < m; ++i)
                    putchar((t&(1<<i)) ? '1' : '0');
                for(int i = m; i < n; ++i)
                    putchar((st&(1<<(i-m))) ? '1' : '0');
                return 0;
            }
        }
    }
    

    E.All men are brothers

    正解:

    •核心就是每次合并考虑减少了多少。
    •减少的数量等于合并的两个集合大小乘以,再乘以从其他集合中选出2个不在一个集合内的方案数
    •从其他集合中选出2个不在一个集合内的方案数可以先计算任选2个的方案数,再减去来自同一个集合的方案数

    貌似这是送分题,但是我不会。

    CODE

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline int gi()
    {
        char c;int num=0,flg=1;
        while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
        while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
        return num*flg;
    }
    #define N 100005
    #define LL unsigned long long
    int fa[N],siz[N];
    int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    int main()
    {
        int n,m,i,p,q;
        LL pw=0;
        n=gi();m=gi();
        for(i=1;i<=n;i++){fa[i]=i;siz[i]=1;pw++;}
        LL ans=1ll*n*(n-1)/2*(n-2)/3;
        if(ans%4==0) ans=1ll*ans/4*(n-3);
        else ans=1ll*(n-3)/4*ans;
        printf("%llu
    ",ans);
        for(i=1;i<=m;i++){
            p=find(gi());q=find(gi());
            if(p!=q){
                pw-=(1ll*siz[p]*siz[p]+1ll*siz[q]*siz[q]);
                ans-=1ll*siz[p]*siz[q]*((1ll*(n-siz[p]-siz[q])*(n-siz[p]-siz[q])-pw)/2);
                fa[q]=p;
                siz[p]+=siz[q];
                pw+=1ll*siz[p]*siz[p];
            }
            printf("%llu
    ",ans);
        }
    }
    

    H.Cutting Bamboos

    二分+主席树 傻逼题

    CODE

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    #define pLi pair<LL, int>
    const int MAXN = 200005;
    struct node {
    	int ls, rs;
    	LL val; int cnt;
    }t[MAXN*50];
    int n, q, rt[MAXN], tot, h[MAXN], c[MAXN];
    inline bool cmp(int x, int y) { return h[x] > h[y]; }
    
    inline void upd(int i) {
    	t[i].val = t[t[i].ls].val + t[t[i].rs].val;
    	t[i].cnt = t[t[i].ls].cnt + t[t[i].rs].cnt;
    }
    void modify(int &i, int l, int r, int x, int p) {
    	t[i = ++tot] = t[p];
    	if(l == r) { t[i].val = h[x]; t[i].cnt = 1; return; }
    	int mid = (l + r) >> 1;
    	if(x <= mid) modify(t[i].ls, l, mid, x, t[p].ls);
    	else modify(t[i].rs, mid+1, r, x, t[p].rs);
    	upd(i);
    }
    inline pLi add(pLi A, pLi B) {
    	return pLi(A.first + B.first, A.second + B.second);
    }
    pLi query(int i, int l, int r, int x, int y) {
    	if(!i) return pLi(0, 0);
    	if(x <= l && r <= y) return pLi(t[i].val, t[i].cnt);
    	int mid = (l + r) >> 1; pLi re = pLi(0, 0);
    	if(x <= mid) re = add(re, query(t[i].ls, l, mid, x, y));
    	if(y > mid) re = add(re, query(t[i].rs, mid+1, r, x, y));
    	return re;
    }
    int main () {
    	scanf("%d%d", &n, &q);
    	for(int i = 1; i <= n; ++i)
    		scanf("%d", &h[i]), c[i] = i;
    	sort(c + 1, c + n + 1, cmp);
    	rt[0] = 0;
    	for(int i = 1; i <= n; ++i)
    		modify(rt[i], 1, n, c[i], rt[i-1]);
    	for(int i = 1; i < n; ++i)
    		if(h[c[i]] == h[c[i+1]]) rt[i] = rt[i+1];
    	while(q-->0) {
    		int l, r, x, y;
    		scanf("%d%d%d%d", &l, &r, &x, &y);
    		double tmp = query(rt[n], 1, n, l, r).first;
    		tmp *= x; tmp /= y;
    		int L = 1, R = n, mid; pLi t;
    		while(L < R) {
    			mid = (L + R + 1) >> 1;
    			t = query(rt[mid], 1, n, l, r);
    			if(t.first - 1ll*t.second*h[c[mid]] <= tmp) L = mid;
    			else R = mid - 1;
    		}
    		t = query(rt[L], 1, n, l, r);
    		double S = t.first - 1ll*t.second*h[c[L]];
    		tmp -= S;
    		printf("%.6f
    ", h[c[L]] - tmp / t.second);
    	}
    }
    

    J. Symmetrical Painting

    相当于多个公差为1的等差数列叠加,然后我写了个线段树被卡空间了。人没了。其实直接差分就行了。

    CODE

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int MAXN = 300005;
    const int MAXM = MAXN*3;
    int n, m;
    double p[MAXM], l[MAXN], r[MAXN], ans[MAXM];
    struct seg {
        int t[MAXM]; double s[MAXM]; int flg;
        void cover(int x, int y, double val) {
            ++t[x], --t[y+1];
            s[x]+=val, s[y+1]-=val;
        }
        void solve() {
            for(int i = 1; i <= m; ++i) {
                t[i] += t[i-1], s[i] += s[i-1];
                if(flg) ans[i] += s[i], ans[i] -= p[i] * t[i];
                else ans[i] += p[i] * t[i], ans[i] -= s[i];
                s[i-1] = t[i-1] = 0;
            }
            s[m] = t[m] = 0;
        }
    }T;
    int main () {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            scanf("%lf%lf", &l[i], &r[i]);
            p[++m] = l[i];
            p[++m] = (l[i]+r[i])/2;
            p[++m] = r[i];
        }
        sort(p + 1, p + m + 1);
        m = unique(p + 1, p + m + 1) - p - 1;
         
        T.flg = 0;
        for(int i = 1; i <= n; ++i) {
            int L = lower_bound(p + 1, p + m + 1, l[i]) - p;
            int R = upper_bound(p + 1, p + m + 1, (l[i]+r[i])/2) - p - 1;
            if(L <= R) T.cover(L, R, l[i]);
        }
        T.solve();
         
        T.flg = 1;
        for(int i = 1; i <= n; ++i) {
            int L = upper_bound(p + 1, p + m + 1, (l[i]+r[i])/2) - p;
            int R = upper_bound(p + 1, p + m + 1, r[i]) - p - 1;
            if(L <= R) T.cover(L, R, r[i]);
        }
        T.solve();
         
        LL ANS = 0;
        for(int i = 1; i <= m; ++i)
            ANS = max(ANS, (LL)(2*ans[i]));
        cout<<ANS<<endl;
    }
    
  • 相关阅读:
    strftime和strptime函数对时间的转换操作
    第四章文件和目录学习笔记
    getenv和putenv在获取和设置环境变量中的使用
    SQL 常用语句以及函数(个人收藏)
    详测 Generics Collections TQueue (2): Create、Count、Clear、TrimExcess
    详测 Generics Collections TQueue (1): Enqueue、Dequeue、Peek
    详测 Generics Collections TList (9): BinarySearch
    详测 Generics Collections TList (8): Sort
    详测 Generics Collections TList (4): AddRange、InsertRange、DeleteRange
    详测 Generics Collections TList (7): Items、Contains
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039251.html
Copyright © 2011-2022 走看看