问题虫洞——A:https://ac.nowcoder.com/acm/contest/889/A


黑洞内窥:



即求斐波那契各项的m次幂的和mod10^9的结果

思维光年:

大佬的做法:

将10^9 拆解为 2^9 和 5^9, 然后可以分别求出Fibonacci在2^9和5^9下的循环节为768 和 7812500

设Ai 为 %2^9的前缀和数组,,设Bi为%5^9的前缀和数组,设C = %10^9,

而我们可以预处理出Ai,和Bi, 然后用CRT(中国剩余定理)合并一下:

题解的做法:





ACcode:

//#include<bits/stdc++.h>
#include  <stdio.h>
#include <iostream>
#include<algorithm>
#include      <map>
#include      <set>
#include   <vector>
#include    <queue>
#include    <stack>
#include <stdlib.h>
#include  <cstring>
#include <string.h>
#include   <string>
#include   <math.h>
#include  <sstream>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define MAXN 50000000
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
const ll mod = 1000000007;
const double eps = 0.0000001;
const double pi = acos(-1);

ll f[MAXN];
ll ans1, ans2, n, m;

ll qpow(ll a, ll b, ll m)
{
    ll ans = 1;
    while(b)
    {
        if(b&1)
            ans = a*ans%m;
        a = a*a%m;
        b >>= 1;
    }
    return ans;
}

///Fibonacci % 2^9的循环节为768
///Fibonacci % 5^9的循环节为7812500
ll solve(int p)
{
    f[0]=0, f[1]=1;
    ll tot=1, ans=0;
    do
    {
        ++tot;
        f[tot] = (f[tot-1] + f[tot-2])%p;
    }while(f[tot]!=0 || f[tot-1]!=1);  ///求循环节

    for(int i=0; i<tot; ++i)
    {
        int k = n/tot;
        if(n%tot >= i)
            ++k;
        ans = (ans+qpow(f[i], m, p)*k)%p;
    }
    return ans;
}

int main()
{
    cin >> n >> m;
    ans1 = solve(512);    //2^9;
    ans2 = solve(1953125);//5^9
    while(ans1%1953125 != ans2)
        ans1+=512;
    cout << ans1 << '\n';
    return 0;
}


问题虫洞——B:https://ac.nowcoder.com/acm/contest/889/B


黑洞内窥:

p = 1000000007
Given two integers b and c, please find two integers x and y(0≤x≤y<p), such that
(x+y)%p=b
(x×y)%p=c
给出上面的组合式,并给出取模后的结果b和c,

求一组解(x, y)

思维光年:

唯一少的一点就是中间那个知识点,不过,即使不用中间那个知识点,自己枚举应该也可以求解,,,




ACcode:

#include<stdio.h>
#include<iostream>
#include<map>
#include<algorithm>
#include<cstring>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
#define MAXN 1000005
#define INF 0x3f3f3f3f//将近int类型最大数的一半,而且乘2不会爆int
#define MOD 1000000007 // MOD%4 = 3

ll qpow(ll a, ll b)
{
    ll ans = 1;
    while(b)
    {
        if(b&1)
            ans = ans*a%MOD;
        a = a*a%MOD;
        b >>= 1;
    }
    return ans;
}

int main()
{
    ll t, x, y, b, c;
    cin >> t;
    while(t--)
    {
        scanf("%lld %lld", &b, &c);
        ll ans = (b*b - 4*c +MOD)%MOD;
        ll a = qpow(ans, (MOD+1)/4);
        if((ll)a*a%MOD != ans)          //不能二次剩余,即无整数解
            puts("-1 -1");
        else
        {
            x = (b+a)*(MOD+1)/2%MOD;    //乘(MOD+!)是为了防止/2溢出
            y = (b-x+MOD)%MOD;
            if(x>y) swap(x, y);
            cout << x << ' ' << y << '\n';
        }
    }
    return 0;
}




问题虫洞——E:https://ac.nowcoder.com/acm/contest/889/E


黑洞内窥:

一开始有N个人不认识。有M次机会吧,他们中的两个轮流交朋友。

朋友关系是相互的、可传递的。

如果A是B的朋友,那么B也是A的朋友。

例如,如果A是B的朋友,B是C的朋友,那么A和C是朋友。

在开始和每个回合之后,请计算从中选择四个人的方法的数量,这样这四个人中的任何两个都不是朋友。

思维光年:

题解很简单,我感觉好像在哪里做过这种题。。。。。

我不知道为什么,压缩版的tofind和递归版的tofind的速度是相同的,而你用普通的tofind就会T,。,,,

ACcode:

//#include<bits/stdc++.h>
#include  <stdio.h>
#include <iostream>
#include<algorithm>
#include      <map>
#include      <set>
#include   <vector>
#include    <queue>
#include    <stack>
#include <stdlib.h>
#include  <cstring>
#include <string.h>
#include   <string>
#include   <math.h>
#include  <sstream>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
//typedef using long long ull;
#define MAXN 200005
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
const ll mod = 1000000007;
const double eps = 0.0000001;
const double pi = acos(-1);

int pre[MAXN];
ull s[MAXN];
//int tofind(int x){return pre[x]!=x?pre[x]=tofind(pre[x]):x;}
int tofind(int x)
{
    int r = x;
    while(r != pre[r])
        r = pre[r];
    int i=x, j;
    while(i!=r)
    {
        j = pre[i];
        pre[i] = r;
        i = j;
    }
    return r;
}

int main()
{
    int n, m, a, b;
    ull c=0, c1=0, c2=0;
    scanf("%d %d", &n, &m);
    c = (ull)n*(n-1)/2*(n-2)/3*(n-3)/4; //总方案数
    cout << c << '\n';
    for(int i=1; i<=n; ++i)
    {
        pre[i] = i;
        s[i] = 1;
        c1+=s[i];
        c2+=s[i]*s[i];
    }
    for(int i=0; i<m; ++i)
    {
        scanf("%d %d", &a, &b);
        int fx = tofind(a);
        int fy = tofind(b);
        if(fx != fy)
        {
            c1-=s[fx]+s[fy];
            c2-=s[fx]*s[fx]+s[fy]*s[fy];
            c-=(c1*c1 - c2)/2 * s[fx]*s[fy];
            s[fy]+=s[fx];                   //合并集合数量
            c1+=s[fy];
            c2+=s[fy]*s[fy];
            pre[fx] = fy;
        }
        cout << c << '\n';
    }
    return 0;
}




问题虫洞——J:https://ac.nowcoder.com/acm/contest/889#question


黑洞内窥:

最初,整个坐标平面为白色。n个长方形被漆成黑色。

第i个矩形的左下角(i-1,li)和右上角(i,ri)表示1≤i≤n。

要将一些黑***域漆成白色,以便剩余的黑色部分具有水平对称轴。

找到剩余黑色部分的最大可能区域。

思维光年:

然而这个过程我仍然模拟不出来。。。。

ACcode:

#include<stdio.h>
#include<iostream>
#include<map>
#include<algorithm>
#include<cstring>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
#define MAXN 1000005
#define INF 0x3f3f3f3f//将近int类型最大数的一半,而且乘2不会爆int
#define MOD 1000000000
 
struct node
{
    ll x, y;
}stu[MAXN];
int cmp(node a, node b) {return a.x < b.x;}
 
int main()
{
    int t, tot=0;
    ll l, r;
    cin >> t;
    while(t--)
    {
        scanf("%lld %lld", &l, &r);
        l<<=1, r<<=1;
        stu[++tot] = {l, 1};
        stu[++tot] = {(l+r)>>1, -2};
        stu[++tot] = {r, 1};
    }
    sort(stu+1, stu+tot+1, cmp);//按点的大小排序
    ll ans=0, p=0, q=0, tem=0;  //这里有点迷~~~
    for(int i=1; i<tot; ++i)
    {
        p += stu[i].y;
        q = stu[i+1].x - stu[i].x;
        tem += p*q;
        ans = max(ans, tem);
    }
    cout << ans << '\n';
    return 0;
}