2019牛客暑期多校训练营(第三场)[DFH]

问题虫洞——D:Big Integer


黑洞内窥:

给出t组样例,每组输入p,n,m,有函数A(n) = n个1,如A(2) = 11, A(5) = 11111, 问有多少对(i,j)使得
在这里插入图片描述


光年之外:

在这里插入图片描述在这里插入图片描述
前面一块的思路感觉是蛮清晰的,后面这么看着看着就有点模糊了。。。。。。

推荐博客:D.Big Integer(费马小定理+找循环节)

代码块:

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
const ll mod = 100000000;
const int MAXN = 200005;

ll t, n, m, p;
ll pi[105], ai[105], cnt, tot;
//ll gcd(ll a, ll b){return b==0? a: gcd(b, a%b);}
ll ksm(ll a, ll b, ll c)
{
    ll ans=1;
    while(b)
    {
        if(b&1)
            ans = ans*a%c;
        a = a*a%c;
        b>>=1;
    }
    return ans;
}

int main()
{
    scanf("%lld", &t);
    while(t--)
    {
        pi[0]=0, cnt=0, tot=0;
        scanf("%lld %lld %lld", &p, &n, &m);
        if(p == 2 || p == 5)
        {
            puts("0");
            continue;
        }
        ll y=p-1, x=p;
        if(p==3)    //最小的循环节为3
            x=3;
        else
        {       //求最小循环节
            for(ll i=2; i*i<=y; ++i)
                if(y%i == 0)
                    if(ksm(10, i, p) == 1)
                        x = min(x, i);
                    else if(ksm(10, y/i, p) == 1)
                        x = min(x, y/i);
            if(ksm(10, p-1, p) == 1)
                x = min(x, p-1);
        }
   
        for(ll i=2; i*i<=x; ++i)//记录质因子和个数,pi[0]用来统计总个数
            if(x%i == 0)
            {
                pi[++pi[0]] = i;
                ai[pi[0]] = 0;
                while(x%i == 0)
                {
                    x/=i;
                    ++ai[pi[0]];
                }
            }
        if(x > 1)
        {
            pi[++pi[0]] = x;
            ai[pi[0]] = 1;
        }
        
        ll maxn=0, ans=0;
        for(ll i=1; i<=pi[0]; ++i)
            maxn = max(maxn, ai[i]);
        for(ll i=1; i<=min(maxn, m); ++i)//按[(质因子每个)/i]回代求g,再ans+=(每个g的贡献)
        
        {
            ll pre = 1;
            for(ll cc, j=1; j<=pi[0]; ++j)
            {
                cc = ai[j]/i + (ai[j]%i!=0);
                while(cc--)
                    pre*=pi[j];
            }
            ans+=n/pre;
        }
        if(m > maxn)        //不再贡献
        {
            ll pre = 1;
            for(ll i=1; i<=pi[0]; ++i)
                pre*=pi[i];
            ans+=1ll*(m-maxn)*(n/pre);
        }
        printf("%lld\n", ans);
    }
    return 0;
}



问题虫洞——F:Planting Trees


黑洞内窥:

给你一个n*n的矩阵, 要你求出最大子矩阵的面积

子矩阵满足最大值和最小值的差值小于等于k.

光年之外:

首先先将二维矩阵压缩成一维的状态

枚举上界和下界的值,将每一列的最大值和最小值记录下来

然后开两个单调队列来记录当前最大值和最小值的位置

最大值单调递减,最小值单调递增

枚举右边界 每次记录下最大的面积
(然而我并不会丫丫丫丫!!!!)

代码块:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
const ll mod = 1000000007;
const int MAXN = 511;

int a[MAXN][MAXN], mxx[MAXN], mii[MAXN], q[MAXN][2], n, k, t;
int main()
{
    cin >> t;
    while(t--)
    {
        scanf("%d %d", &n, &k);
        for(int i=1; i<=n; ++i)
            for(int j=1; j<=n; ++j)
                scanf("%d", &a[i][j]);
        int ans = 1;
        for(int i=1; i<=n; ++i)
        {
            for(int j=1; j<=n; ++j)
            {
                mxx[j] = -mod;
                mii[j] = mod;
            }
            for(int j=i; j<=n; ++j)
            {
                for(int k=1; k<=n; ++k)
                {
                    mxx[k] = max(mxx[k], a[j][k]);
                    mii[k] = min(mii[k], a[j][k]);
                }
                int l=1, h0=0, t0=1, h1=0, t1=1;
                for(int r=1; r<=n; ++r)
                {
                    while(t0 <= h0 && mxx[r] >= mxx[q[h0][0]]) h0--;
                    while(t1 <= h1 && mii[r] <= mii[q[h1][1]]) h1--;
                    q[++h0][0] = r;
                    q[++h1][1] = r;
                    while(l<=r && mxx[q[t0][0]] - mii[q[t1][1]] > k)
                    {
                        l++;
                        if(q[t0][0] < l) t0++;
                        if(q[t1][1] < l) t1++;
                    }
                    ans = max(ans, (r-l+1)*(j-i+1));
                }
            }
        }
        cout << ans << '\n';
    }
  return 0;
}




问题虫洞——H:Magic Line


黑洞内窥:

有t组样例,每组样例给出n个坐标,且n为偶数,n<=1000,
求一条将n个点平分的直线,并输出该直线上的任意两点。


光年之外:

按照x,y排序一遍,在中点坐标做一条极度倾斜的直线即可,(注意y的值不能相同)

在这里插入图片描述


#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
const ll mod = 100000000;
const int MAXN = 200005;

struct node
{
    ll x, y;
} stu[MAXN];

ll cmp(node a, node b)
{
    if(a.x == b.x)
        return a.y > b.y;
    return a.x < b.x;
}
int main()
{
    ll n, t;
    scanf("%lld", &t);
    while(t--)
    {
        scanf("%lld", &n);
        for(int i=1; i<=n; ++i)
            scanf("%lld%lld", &stu[i].x, &stu[i].y);
        sort(stu+1, stu+n+1, cmp);
        printf("%lld %lld %lld %lld\n", stu[n/2].x-1, stu[n/2].y-mod-1, stu[n/2].x+1, stu[n/2].y+mod);
    }//注意这里的两处y要相差1,是为了避免过那个点,,,
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值