2019牛客多校第三场

B.Crazy Binary String

最长子序列直接找000111中较少的那个即可
对于最长子串,把000看作−1-11的话,即找区间和为000的最长区间
数组记录前缀和出现的最早位置就可以了

#include<bits/stdc++.h>
#define N 500000
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int n,i,base,res,x,y;
int pos[N],a[N],s[N];
char ch[N];
int main()
{
    scanf("%d",&n);
    scanf("%s",ch+1);
    fo(i,1,n) if (ch[i] == '0') a[i] = 1; else a[i] = -1;
    fo(i,1,n) s[i] = s[i-1] + a[i];
    base = n;
    fo(i,1,n)
    {
        if (pos[s[i]+base] == 0 && s[i] != 0) {pos[s[i]+base] = i; continue;}
        res = max(res,i-pos[s[i]+base]);
    }
    cout<<res<<" ";
    fo(i,1,n) if (a[i] == 1) x++; else y++;
    cout<<min(x,y)*2<<endl;
    return 0;
}

D.Big Integer

111...111=10n−19≡0(mod111...111=\frac { { 10 }^{ n }-1 }{ 9 } \equiv 0(mod111...111=910n10(mod p)p)p),等价于10n≡1(mod10^n \equiv 1(mod10n1(mod 9p)9p)9p)
p=2,5p=2,5p=2,5时答案显然为0,否则有10φ(9p)≡1(mod10^{\varphi(9p)}\equiv1(mod10φ(9p)1(mod 9p)9p)9p)
我们需要找到10i10^i10i modmodmod 9p9p9p的循环节d,那么有ddd ∣| φ(9p)\varphi(9p)φ(9p),暴力枚举φ(9p)\varphi(9p)φ(9p)的约数即可,之后问题转化为求ddd ∣| iji^jij的组数
(ps:这里做快速幂有可能爆long long,当然std用了另一种做法,即特判掉ppp999不互质的情况,然后就没有这个999了)
这是一个经典的问题,设d=p1k1p2k2...plkld=p_{1}^{k_1}p_{2}^{k_2}...p_{l}^{k_l}d=p1k1p2k2...plkl
对于一个jjj,设g=p1⌈k1j⌉p2⌈k2j⌉...pl⌈klj⌉g=p_{1}^{\lceil \frac{k_1}{j} \rceil}p_{2}^{\lceil \frac{k_2}{j} \rceil}...p_{l}^{\lceil \frac{k_l}{j} \rceil}g=p1jk1p2jk2...pljkl,则iii必须是ggg的倍数
然后可以发现j&gt;30j &gt; 30j>30之后ggg不会变化(因为ki≤30k_i \le 30ki30),直接乘起来即可

#include<iostream>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define N 100
using namespace std;
long long T,n,m,i,j,k;
long long d,p,g,res;
long long prime[N],exp1[N],expp[N];
long long qm(long long a,long long x,long long mod)
{
    __int128_t res = 1; __int128_t e = a;
    //long long res = 1; long long e = a;
    while (x)
    {
        if (x&1) res = (res * e) % mod;
        e = (e * e) % mod;
        x = x / 2;
    }
    return res;
}
bool check(long long x)
{
    if (qm(10,x,9*p) == 1)
        return true;
    else return false;
}
int main()
{
    scanf("%lld",&T);
    while (T--)
    {
        res = 0;
        scanf("%lld%lld%lld",&p,&n,&m);
        if (p == 2 || p == 5) {printf("0\n"); continue;}
        long long pp = 6 * (p - 1);
        d = pp;
        fo(i,2,sqrt(pp))
        if ((pp) % i == 0)
        {
            if (check(i)) d = min(d,i);
            if (check(pp/i)) d = min(d,pp/i);
        }
        //cout<<d<<endl<<endl;
        k = 0;
        fo(i,2,sqrt(d))
        if (d % i == 0)
        {
            k++; prime[k] = i; exp1[k] = 0;
            while (d % i == 0)
            {
                exp1[k]++; d = d / i;
            }
        }
        if (d > 1) {k++; prime[k] = d; exp1[k] = 1;}
        fo(j,1,min(1ll*30,m))
        {
            fo(i,1,k)
            {
                expp[i] = exp1[i] / j;
                if (exp1[i] % j > 0) expp[i]++;
            }
            g = 1;
            fo(i,1,k)
            if (g <= n)
                while (expp[i]--)
                {
                    g = g * prime[i];
                    if (g > n) break;
                }
            else break;
            res += n / g;
        }
        if (m > 30) res += 1ll * (n / g) * (m - 30);
        printf("%lld\n",res);
    }
    return 0;
}

G.Removing Stones

显然,最多的一堆不能超过总和的一半
那么我们可以每次找到区间的最大值的位置kkk,左右两个区间中,枚举落在较小的区间的端点的位置,另外一个端点可以二分得到(因为区间越长,区间和越大,越有可能是答案)
然后分成两半继续递归
注意这里必须较小区间枚举、较大区间二分,否则有可能退化为N2N^2N2
第一次用线段树找区间最大值T了,后来改成ST表才过掉
当然这里还有许多小优化,比如二分区间单调变小,找不到了可以退出等等。。。。
但是用线段树是一定不行的,因为线段树的复杂度是跑满的(甚至应该是大于)O(Nlog2N)O(Nlog^2N)O(Nlog2N)

#include<iostream>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define N 300005
using namespace std;
int mx[N*4];
int st[N][20];
int n,i,T;
long long res;
long long sum[N],a[N];
void build(int rt,int l,int r)
{
    if (l == r) {mx[rt] = a[l]; return;}
    int mid = (l + r) >> 1;
    build(rt<<1,l,mid); build(rt<<1|1,mid+1,r);
    mx[rt] = max(mx[rt<<1],mx[rt<<1|1]);
}
int query(int rt,int l,int r,int L,int R)
{
    if (l == r) return l;
    int mid = (l + r) >> 1;
    int x=-1,y=-1;
    if (L <= mid) x = query(rt<<1,l,mid,L,R);
    if (mid+1 <= R) y = query(rt<<1|1,mid+1,r,L,R);
    if (x == -1) return y; else if (y == -1) return x; else
        if (a[x] >= a[y]) return x; else return y;
}
int query2(int l,int r)
{
    int len = r - l + 1;
    int p = log(len)/log(2);
    int x = st[l][p];
    int y = st[r-(1<<p)+1][p];
    if (a[x] < a[y]) return y; else return x;
}
void dfs(int l,int r)
{
    if (r -l + 1 < 2) return;
    int k,ll,rr,L,R,p;
    k = query2(l,r);
    if (k <= ((l + r) >> 1))
    {
        L = k; R = r; p = -1;
        fo(ll,l,k)
        {
            //if (p == -1) {L = k; R = r;} else {L = p; R = r; p = -1;}
            L = k; R = r; p = -1;
            while (L <= R)
            {
                int mid = (L + R) >> 1;
                if ((sum[mid] - sum[ll-1]) / 2 >= a[k]) {p = mid; R = mid - 1;}
                else L = mid + 1;
            }
            if (p != -1) res += r - p + 1;// else break;
        }
    }   else
    {
        L = l; R = k; p = -1;
        fd(rr,r,k)
        {
            //if (p == -1) {L = l; R = k;} else {L = l; R = p; p = -1;}
            L = l; R = k; p = -1;
            while (L <= R)
            {
                int mid = (L + R) >> 1;
                if ((sum[rr] - sum[mid-1]) / 2 >= a[k]) {p = mid; L = mid + 1;}
                else R = mid - 1;
            }
            if (p != -1) res += p - l + 1;// else break;
        }
    }
    dfs(l,k-1); dfs(k+1,r);
}
void ST()
{
    int i,j,x,y,len;
    fo(i,1,n) st[i][0] = i;
    fo(j,1,log(n)/log(2))
    {
        len = 1 << j;
        fo(i,1,n-len+1)
        {
            x = st[i][j-1]; y = st[i+len/2][j-1];
            if (a[x] < a[y]) st[i][j] = y; else st[i][j] = x;
        }
    }
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        fo(i,1,n) scanf("%d",&a[i]);
        ST();
        fo(i,1,n) sum[i] = sum[i-1] + a[i];
        //build(1,1,n);
        res = 0;
        dfs(1,n);
        cout<<res<<endl;
    }
    return 0;
}



H.Magic Line

让你找一条直线平分平面上的nnn个点
按照xxx升序,再按照yyy降序排序,找到第n/2n/2n/2个点
以这个点作竖直线,然后往顺时针转一点点,就可以把左上和右下分开

#include <bits/stdc++.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define N 1005
using namespace std;
struct www{int x,y;} f[N];
int T,n,i,mid;
bool cmp(const www &a,const www &b) {if (a.x != b.x) return a.x < b.x; else return a.y > b.y;}
void print(int a,int c,int b,int d)
{
    int q = 900000000;
    int x1,y1,x2,y2;
    if ((a+b)%2 == 0) {x1 = (a+b)/2+1; x2 = (a+b)/2-1;} else {x1 = (a+b)/2+1; x2 = (a+b)/2;}
    if ((c+d)%2 == 0) {y1 = (c+d)/2+1+q; y2 = (c+d)/2-1-q;} else {y1=(c+d)/2+1+q; y2 = (c+d)/2-q;}
    printf("%d %d %d %d\n",x1-N,y1-N,x2-N,y2-N);
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        fo(i,1,n) scanf("%d%d",&f[i].x,&f[i].y);
        fo(i,1,n) {f[i].x+=N; f[i].y+=N;}
        sort(f+1,f+n+1,cmp);
        mid = n / 2;
        print(f[mid].x,f[mid].y,f[mid+1].x,f[mid+1].y);
    }
}
资源下载链接为: https://pan.quark.cn/s/9648a1f24758 这个HTML文件是一个专门设计的网页,适合在告白或纪念日这样的特殊时刻送给女朋友,给她带来惊喜。它通过HTML技术,将普通文字转化为富有情感和创意的表达方式,让数字媒体也能传递深情。HTML(HyperText Markup Language)是构建网页的基础语言,通过标签描述网页结构和内容,让浏览器正确展示页面。在这个特效网页中,开发者可能使用了HTML5的新特性,比如音频、视频、Canvas画布或WebGL图形,来提升视觉效果和交互体验。 原本这个文件可能是基于ASP.NET技术构建的,其扩展名是“.aspx”。ASP.NET是微软开发的一个服务器端Web应用程序框架,支持种编程语言(如C#或VB.NET)来编写动态网页。但为了在本地直接运行,不依赖服务器,开发者将其转换为纯静态的HTML格式,只需浏览器即可打开查看。 在使用这个HTML特效页时,建议使用Internet Explorer(IE)浏览器,因为一些老的或特定的网页特效可能只在IE上表现正常,尤其是那些依赖ActiveX控件或IE特有功能的页面。不过,由于IE逐渐被淘汰,现代网页可能不再对其进行优化,因此在其他现代浏览器上运行可能会出现问题。 压缩包内的文件“yangyisen0713-7561403-biaobai(html版本)_1598430618”是经过压缩的HTML文件,可能包含图片、CSS样式表和JavaScript脚本等资源。用户需要先解压,然后在浏览器中打开HTML文件,就能看到预设的告白或纪念日特效。 这个项目展示了HTML作为动态和互动内容载体的强大能力,也提醒我们,尽管技术在进步,但有时复古的方式(如使用IE浏览器)仍能唤起怀旧之情。在准备类似的个性化礼物时,掌握基本的HTML和网页制作技巧非常
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值