2019南昌ICPC网络赛部分题解 A Subsequence M Subsequence H. Coloring Game K. MORE XOR I Max answer

A Subsequence 

题意:求前五个完美数。

思路:完全数:又称完美数,完备数。所有除了自身以外的约数的和,恰好等于它本身。目前共发现48个完美数。(好像说完美数一定是以6或者8结尾。)

前9个完美数分别为:6、28、496、8128、33550336、8589869056、137438691328、2305843008139952128、2658455991569831744654692615953842176。

欧拉曾推出完美数的公式:如果p是质数,且2^p-1也是质数,那么(2^p-1)*2^(p-1)便是一个完全数。

利用上述性质即可打印出前几个完美数,然后大表即可。

打表代码:(至于为什么而打印出来的完美数一定是前几个......我也不知道)

 

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<sstream>
#include<cstdlib>
#include<time.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define repp(i,n,a) for(int i=n;i>=a;i--)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define Eps 1e-8
#define Mod 1e9+7
#define maxn 100010
const double pi=acos(-1.0);
using namespace std;
const int N=10000010;
bool prime[N];
void init()
{
    mem(prime,true);
    prime[0]=false;
    prime[1]=false;
    rep(i,1,N-1)
    {
        if(prime[i])
            for(int j=2;i*j<N-1;j++)
                prime[i*j]=false;
    }
}
ll pow_mod(int a,int b)
{
    ll ret=1;
    while(b)
    {
        if(b&1)
            ret*=a;
        a=a*a;
        b/=2;
    }
    return ret;
}
int main()
{
    init();
    rep(i,2,N-1)
    {
        if(prime[i]&&prime[pow_mod(2,i)-1])
            cout<<(pow_mod(2,i)-1)*pow_mod(2,i-1)<<endl;
    }
    return 0;
}

 AC code:

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<sstream>
#include<cstdlib>
#include<time.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define repp(i,n,a) for(int i=n;i>=a;i--)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define Eps 1e-8
#define Mod 1e9+7
#define maxn 100010
const double pi=acos(-1.0);
using namespace std;

int main()
{
    cout<<"6"<<endl;
    cout<<"28"<<endl;
    cout<<"496"<<endl;
    cout<<"8128"<<endl;
    cout<<"33550336"<<endl;
    return 0;
}

M Subsequence

题意:给一个主串S,询问n次,每次给出一个串Ti,问Ti是否为S的子序列。

用 nxt [i] [j] 记录位置 i 后 j 第一次出现的位置。查询直接往后跳即可。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<sstream>
#include<cstdlib>
#include<time.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define repp(i,n,a) for(int i=n;i>=a;i--)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define Eps 1e-8
#define Mod 1e9+7
#define maxn 100010
const double pi=acos(-1.0);
using namespace std;
char s[100010];
char t[1010];
int nex[100010][30];
void getnext()
{
    rep(i,0,100009)
        rep(j,0,29)
            nex[i][j]=-1;
    int len=strlen(s+1);
    repp(i,len,1)
    {
        int a=s[i]-'a'+1;
        rep(j,1,26)
        {
            if(j==a)
                nex[i-1][j]=i;
            else
                nex[i-1][j]=nex[i][j];
        }
    }
    rep(i,1,26)
    {
        if(s[1]-'a'+1==i)
            nex[0][i]=1;
        else
            nex[0][i]=nex[1][i];
    }
}
int main()
{
    scanf("%s",s+1);
    getnext();
    int n;
    cin>>n;
    while(n--)
    {
        scanf("%s",t+1);
        int tlen=strlen(t+1);
        int p=0;
        int f=0;
        rep(i,1,tlen)
        {
            p=nex[p][t[i]-'a'+1];
            if(p==-1)
                {f++;break;}
        }
        if(f==0)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}

H. Coloring Game 

思维,推公式,左下角那个格有两种情况,右上角那个格有两种情况,左上角和右下角只有一种情况,其他的格有三种情况,所以答案就是 2*2*(3^(n-2))%mod ,快速幂一下就行了。当n等1的时候需要特判一下。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<sstream>
#include<cstdlib>
#include<time.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define repp(i,n,a) for(int i=n;i>=a;i--)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define Eps 1e-8
#define Mod 1000000007
#define maxn 100010
const double pi=acos(-1.0);
using namespace std;
ll pow_mod(ll a,ll b,ll mod)
{
    ll ret=1;
    while(b)
    {
        if(b&1)
            {ret=(ret*a)%mod;b--;}
        a=(a*a)%mod;
        b>>=1;
    }
    return ret;
}
int main()
{
    ll n;
    cin>>n;
    if(n==1)
        {cout<<"1";return 0;}
    cout<<4*pow_mod(3,n-2,Mod)%Mod<<endl;
    return 0;
}

K. MORE XOR 

通过打表能推出公式, r 和 l 的差值每个4个一循环。

这题用cout竟然会超时,改成printf就过了,真的是......以后干脆都不用cin cout了,都改成scanf printf算了......

打表代码:

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<sstream>
#include<cstdlib>
#include<time.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define repp(i,n,a) for(int i=n;i>=a;i--)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define Eps 1e-8
#define Mod 1e9+7
#define maxn 100010
const double pi=acos(-1.0);
using namespace std;
int a[1010];
int f[110][110],g[110][110],w[110][110];
void ff(int x,int y)
{
    rep(i,x,y)
        {a[i]++;}//a[j]++;}
}
void gg(int x,int y)
{
    rep(i,x,y)
        rep(j,i,y)
            ff(i,j);
}
int main()
{
    int n;
    cin>>n;
    rep(i,1,n)
        a[i]=i;
    int q;
    cin>>q;
    int l,r;
    while(q--)
    {
        scanf("%d%d",&l,&r);
        mem(a,0);
        rep(i,l,r)
            rep(j,i,r)
            {
                gg(i,j);
            }
        rep(i,l,r)
            if(a[i]%2==1)
                cout<<"##"<<i<<endl;
        cout<<endl;
    }
    return 0;
}
/*
100
1000
1 1
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
1 11
1 12
1 13
1 14
1 15
1 16
1 17
1 18
1 19
1 20


2 2
2 3
2 4
2 5
2 6
2 7
2 8
2 9
2 10
2 11
2 12
2 13
2 14
2 15
2 16
2 17
2 18
2 19
2 20

*/

AC code:

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<sstream>
#include<cstdlib>
#include<time.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define repp(i,n,a) for(int i=n;i>=a;i--)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define Eps 1e-8
#define Mod 1e9+7
#define maxn 100010
const double pi=acos(-1.0);
using namespace std;
int a[100010];
int b[100010];
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        mem(a,0);
        mem(b,0);
        int n;
        scanf("%d",&n);
        rep(i,1,n)
            scanf("%d",&a[i]);
        b[1]=a[1];
        b[2]=a[2];
        b[3]=a[3];
        b[4]=a[4];
        rep(i,5,n)
            b[i]=b[i-4]^a[i];
        int q,l,r;
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d%d",&l,&r);
            if((r-l+1)%4==0)
            {
                printf("0\n");
                continue;
            }
                //{cout<<"0"<<endl;continue;}
            if((r-l+1)%4==1)
            {
                if(l>4)
                    printf("%d\n",(b[l+(r-l)/4*4]^b[l-4]));
                    //cout<<(b[l+(r-l)/4*4]^b[l-4])<<endl;
                else
                    printf("%d\n",b[l+(r-l)/4*4]);
                    //cout<<b[l+(r-l)/4*4]<<endl;
                continue;
            }
            if((r-l+1)%4==2)
            {
                int ans=0;
                if(l>4)
                    ans^=b[l+(r-l)/4*4]^b[l-4];
                else
                    ans^=b[l+(r-l)/4*4];
                l++;
                if(l>4)
                    ans^=b[l+(r-l)/4*4]^b[l-4];
                else
                    ans^=b[l+(r-l)/4*4];
                printf("%d\n",ans);
                //cout<<ans<<endl;
                continue;
            }
            if((r-l+1)%4==3)
            {
                l++;
                if(l>4)
                    printf("%d\n",(b[l+(r-l)/4*4]^b[l-4]));
                    //cout<<(b[l+(r-l)/4*4]^b[l-4])<<endl;
                else
                    printf("%d\n",b[l+(r-l)/4*4]);
                    //cout<<b[l+(r-l)/4*4]<<endl;
                continue;
            }
        }
    }
    return 0;
}

I Max answer

题意:求 “ 区间最小值 * 区间和 ” 的最大值。

思路:二分 + ST表求区间最值 + 线段树求区间最大子段和

用dp[i] 表示以 a [i] 为最小值的所有区间中答案最大的值,那么把dp数组求出来了,只需要枚举一遍找最大值就行了。

当 a[i] 为正数的时候,只需要让这个区间的区间和尽可能的大;当 a[i] 为负数的时候,只需要让这个区间的区间和尽可能的小;

求指定区间的最大子段和和最小子段和,我们可以用线段树来做。

那么怎样求以 a[i] 为最小值的最长区间呢(因为区间越长,那么区间的最大子段和才会越大,最小子段和才会越小)?我们可以二分,用ST表O(1)查询区间最值,然后进行二分。

下面的代码中二分写的有点乱,也是自己写了几组样例然后改来改去......

AC code:

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<sstream>
#include<cstdlib>
#include<time.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define repp(i,n,a) for(int i=n;i>=a;i--)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define Eps 1e-8
#define Mod 1e9+7
#define maxn 100010
const double pi=acos(-1.0);
using namespace std;
const int SIZE=500010;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define sum(x) tree[x].sum
#define add(x) tree[x].add

struct node{
    ll l,r;
    ll sum,lmax,rmax,dat;
    ll lmin,rmin,datt;
}t[SIZE*4];
ll a[SIZE],n,m;
ll ff[SIZE][20];
ll x;
void build(ll p,ll l,ll r)
{
    t[p].l=l;
    t[p].r=r;
    if(l==r)
    {
        scanf("%lld",&x);
        a[l]=x;
        t[p].dat=t[p].lmax=t[p].rmax=t[p].sum=x;
        t[p].datt=t[p].lmin=t[p].rmin=t[p].sum=x;
        return ;
    }
    ll mid=(l+r)/2;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    t[p].sum=t[p*2].sum+t[p*2+1].sum;
    t[p].lmax=max(t[p*2].lmax,t[p*2].sum+t[p*2+1].lmax);
    t[p].rmax=max(t[p*2+1].rmax,t[p*2+1].sum+t[p*2].rmax);
    t[p].dat=max(max(t[p*2].dat,t[p*2+1].dat),t[p*2].rmax+t[p*2+1].lmax);

    t[p].lmin=min(t[p*2].lmin,t[p*2].sum+t[p*2+1].lmin);
    t[p].rmin=min(t[p*2+1].rmin,t[p*2+1].sum+t[p*2].rmin);
    t[p].datt=min(min(t[p*2].datt,t[p*2+1].datt),t[p*2].rmin+t[p*2+1].lmin);
}

void change(ll p,ll x,ll y)
{
    if(t[p].l==x&&t[p].r==x)
    {
        t[p].dat=t[p].lmax=t[p].rmax=t[p].sum=y;
        return ;
    }
    ll mid=(t[p].l+t[p].r)/2;
    if(mid<x) change(p*2+1,x,y);
    else  change(p*2,x,y);
    t[p].sum=t[p*2].sum+t[p*2+1].sum;
    t[p].lmax=max(t[p*2].lmax,t[p*2].sum+t[p*2+1].lmax);
    t[p].rmax=max(t[p*2+1].rmax,t[p*2+1].sum+t[p*2].rmax);
    t[p].dat=max(max(t[p*2].dat,t[p*2+1].dat),t[p*2].rmax+t[p*2+1].lmax);
}
node ask(ll p,ll l,ll r){//[l,r]询问的区间    ask(1,x,y)
    if(t[p].l>=l&&t[p].r<=r){
        return t[p];
    }
    ll mid=(t[p].l+t[p].r)>>1;
    if(mid<l)return ask(p<<1|1,l,r);
    else if(mid>=r)return ask(p<<1,l,r);
    else
    {
        node a,b;
        a=ask(p<<1,l,r);
        b=ask(p<<1|1,l,r);
        node tt;
        tt.dat=max(max(a.dat,b.dat),a.rmax+b.lmax);
        tt.lmax=max(a.lmax,a.sum+b.lmax);
        tt.rmax=max(b.rmax,a.rmax+b.sum);

        tt.datt=min(min(a.datt,b.datt),a.rmin+b.lmin);
        tt.lmin=min(a.lmin,a.sum+b.lmin);
        tt.rmin=min(b.rmin,a.rmin+b.sum);

        tt.sum=a.sum+b.sum;
        return tt;
    }
}

void ST_prework()   //ST表O(n* log n)预处理
{
    for(ll i=1;i<=n;i++)
        ff[i][0]=a[i];
    ll t=log(n)/log(2)+1;
    for(ll j=1;j<t;j++)
        for(ll i=1;i<=n-(1<<j)+1;i++)
            ff[i][j]=min(ff[i][j-1],ff[i+(1<<(j-1))][j-1]);
}
ll ST_query(ll l,ll r)  
{
    ll k=log(r-l+1)/log(2);
    return min(ff[l][k],ff[r-(1<<k)+1][k]);
}

ll findp1(ll x) 
{
    if(x==1)
        return 1;
    ll l=1,r=max((ll)1,x-1);
    while(l<=r)
    {
        ll mid=(l+r)>>1;
        if(ST_query(mid,r)<a[x])
            l=mid+1;
        else
            r=mid-1;
    }
    if(ST_query(r,x-1)>a[x])
        return max(min(x,r),(ll)1);
    if(ST_query(l,x-1)>a[x])
        return max(min(x,l),(ll)1);
    else
        return max(min(x,l+1),(ll)1);
}
ll findp2(ll x)
{
    if(x==n)
        return n;
    ll l=min(x+1,n),r=n;
    while(l<=r)
    {
        ll mid=(l+r)>>1;
        if(ST_query(l,mid)<a[x])
            r=mid-1;
        else
            l=mid+1;
    }
    if(ST_query(l,x+1)>a[x])
        return min(max(x,l),n);
    if(ST_query(r,x+1)>a[x])
        return min(max(x,r),n);
    else
        return min(max(x,r-1),n);
}
ll dp[500010];
int main()
{
    cin>>n;
    build(1,1,n);
    ST_prework();   //ST表预处理
    rep(i,1,n)
    {
        dp[i]=a[i]*a[i];    //对dp数组初始化
        ll p1=1,p2=n;
        p1=findp1(i);   //寻找以a[i]为最小值的区间的左端点
        p2=findp2(i);   //寻找以a[i]为最小值的区间的右端点
        node q1=ask(1,p1,i);    //线段树计算a[p1]到a[i]中以a[i]为结尾的最大子段和和最小子段和  时间O(log n)
        node q2=ask(1,i,p2);    //线段树计算a[i]到a[p2]中以a[i]为起始的最大子段和和最小子段和  时间O(log n)
        if(a[i]>0)
            dp[i]=max(dp[i],(q1.rmax+q2.lmax-a[i])*a[i]);
        if(a[i]<0)
            dp[i]=max(dp[i],(q1.rmin+q2.lmin-a[i])*a[i]);
    }
    ll ans=-10;
    rep(i,1,n)
        {ans=max(ans,dp[i]);}
    cout<<ans<<endl;
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值