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\n", 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\n",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\n",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\n", 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;
}
posted @ 2019-12-14 14:50  _Ark  阅读(147)  评论(0编辑  收藏  举报