牛客挑战赛34 A~E

与世无争的帅哥 提交于 2019-12-05 08:36:16

闷声发大财

A

O(nmk)dp即可,因为带了1/2的常数+2s所以很稳

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
using namespace std;

int a[801];
int p[801][801];
long long f[801][801];
int n,m,i,j,k,l,K,Y;

int main()
{
//  freopen("a.in","r",stdin);
    
    scanf("%d%d%d%d",&n,&m,&K,&Y);
    fo(i,1,n)
    scanf("%d",&a[i]);
    fo(i,1,n)
    {
        fo(j,1,m)
        {
            scanf("%d",&p[i][j]);
            
            if (j<Y)
            p[i][j]+=a[i]*j;
        }
    }
    
    memset(f,127,sizeof(f));
    f[0][0]=0;
    
    fo(i,0,n-1)
    {
        fo(j,0,K)
        if (f[i][j]<800000000000ll)
        {
            fd(k,min(K-j,m),0)
            f[i+1][j+k]=min(f[i+1][j+k],f[i][j]+p[i+1][k]);
        }
    }
    
    printf("%lld\n",f[n][K]);
}

B

m=2的约瑟夫问题,给出一个人求n=1~n时剩下这个人的方案&最大的n

约瑟夫的O(n)递推显然过不了,但是随便打表可以发现答案长这样:

1 1 3 1 3 5 7 1 3 5 7 9 11 13 15 1...

随便算

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
using namespace std;

//int f[233];
long long n,m,s,S,ans1,ans2;

int main()
{
//  freopen("b.in","r",stdin);
    
    scanf("%lld%lld",&n,&m);
    
    if (!(m&1))
    {
        printf("0 0\n");
        return 0;
    }
    
    S=0;s=1;
    while (n)
    {
        if (n>=s)
        {
            n-=s;
            if (m<=s*2-1)
            ++ans1,ans2=S+(m+1)/2;
        }
        else
        {
            if (m<=n*2-1)
            ++ans1,ans2=S+(m+1)/2;
            
            n=0;
        }
        
        S+=s;
        s=s*2;
    }
    
    printf("%lld %lld\n",ans1,ans2);
    return 0;
    
//  f[1]=0;
//  fo(i,2,100)
//  f[i]=(f[i-1]+2)%i;
//  
//  fo(i,1,100)
//  cout<<f[i]+1<<" ";
//  if (!f[i])
//  cout<<f[i-1]+1<<" ";
}

C

在普通循环同构的基础上加上了对角互换

懒得画

假设有一条直线穿过圆,并且保证直线上方的数<=对应的直线下方的数

这样解决了对角互换的条件

然后将圆旋转,可以发现上下两部分同时旋转了

于是可以把一对对应点看成一个元素,那么变成元素种数为m(m+1)/2,环的大小为n的普通轮换问题

直接O(n)枚举会挂,所以枚举gcd,再乘上phi(n/gcd)即可

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define mod 19260817
#define Mod 19260815
using namespace std;

int f[mod+1];
int p[1226565];
int T,i,j,k,l,len,s;
long long n,m,ans;

void init()
{
    int i,j;
    
    fo(i,1,mod) f[i]=i;
    
    fo(i,2,mod)
    {
        if (f[i]==i)
        {
            --f[i];
            p[++len]=i;
        }
        
        fo(j,1,len)
        if ((long long)i*p[j]<=mod)
        {
            if (!(i%p[j]))
            {
                f[i*p[j]]=f[i]*p[j];
                break;
            }
            else
            f[i*p[j]]=f[i]*(p[j]-1);
        }
        else
        break;
    }
}

long long qpower(long long a,int b)
{
    long long ans=1;
    
    while (b)
    {
        if (b&1)
        ans=ans*a%mod;
        
        a=a*a%mod;
        b>>=1;
    }
    
    return ans;
}

int gcd(int n,int m)
{
    int r=n%m;
    
    while (r)
    {
        n=m;
        m=r;
        r=n%m;
    }
    
    return m;
}

int main()
{
//  freopen("c.in","r",stdin);
    
    init();
    
    scanf("%d",&T);
    for (;T;--T)
    {
        scanf("%lld%lld",&n,&m);
        m=m*(m+1)/2%mod;
        
        s=floor(sqrt(n));
        
        ans=0;
        fo(i,1,s)
        if (!(n%i))
        {
            ans=(ans+qpower(m,i)*f[n/i]%mod)%mod;
            if (i*i!=n)
            ans=(ans+qpower(m,n/i)*f[i]%mod)%mod;
        }
//      ans=(ans+qpower(m,gcd(n,i)))%mod;
        ans=ans*qpower(n,Mod)%mod;
        
        printf("%lld\n",ans);
    }
}

D

sb题

把平面旋转45°再扩大\(\sqrt{2}\)倍(即(x,y)-->(x+y,y-x)),变成D*D的矩形操作

排序+扫描线

注意边界不能减

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define low(x) (x&-(x))
#define N 200001
using namespace std;

struct type{
    int x,y,s;
} a[200001];
int tr[4*N+1];
int tot,n,D,L,i,j,k,l,x,y,sum;
long long ans;

bool cmp(type a,type b)
{
    return a.x<b.x || a.x==b.x && a.s<b.s;
}

void change(int t,int l,int r,int x,int s)
{
    int mid=(l+r)/2;
    
    tr[t]+=s;
    
    if (l==r)
    return;
    
    if (x<=mid)
    change(t*2,l,mid,x,s);
    else
    change(t*2+1,mid+1,r,x,s);
}

int find(int t,int l,int r,int x,int y)
{
    int mid=(l+r)/2,ans=0;
    
    if (x<=l && r<=y)
    return tr[t];
    
    if (x<=mid)
    ans+=find(t*2,l,mid,x,y);
    if (mid<y)
    ans+=find(t*2+1,mid+1,r,x,y);
    
    return ans;
}

int main()
{
//  freopen("d.in","r",stdin);
    
    scanf("%d%d%d",&n,&D,&L);
    fo(i,1,n)
    {
        scanf("%d%d",&x,&y);
        
        j=x;k=y;
        x=j+k;
        y=k-j;
        
        a[++tot]={x,y,1};
        a[++tot]={x+D,y,-1};
    }
    
    sort(a+1,a+tot+1,cmp);
    
    fo(i,1,tot)
    {
        if (a[i].s==1)
        {
            ans+=sum-find(1,1,N,max(a[i].y+100001-D+1,1),min(a[i].y+100001+D-1,N));
            ++sum;
        }
        
        change(1,1,N,a[i].y+100001,a[i].s);
    }
    
    printf("%lld\n",ans);
}

E

用总数-没有交点的即可,删除可以看成加了一个-1的矩形

求出每个询问上下左右的矩形个数,再减去四个角上的

注意时间也算一维(不用排序),所以需要cdq

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define low(x) (x&-(x))
using namespace std;

struct type{
    int x1,y1,x2,y2,s,id;
} a[100001],b[100001];
struct Type{
    int s,id;
} c[200001];
struct type1{
    int x,s,id;
} d[100001];
struct type2{
    int x,y,s,id,Id;
} D[100001];
int tr[200001];
int ans[200001];
int n,i,j,k,l,tp,tot,Tot,sum,len;

bool Cmp(Type a,Type b) {return a.s<b.s;}
bool cmp(type2 a,type2 b) {return a.x<b.x || a.x==b.x && a.id>b.id;}

void change(int t,int s)
{
    while (t<=200000)
    {
        tr[t]+=s;
        t+=low(t);
    }
}

void clear(int t)
{
    while (t<=200000)
    {
        tr[t]=0;
        t+=low(t);
    }
}

int find(int t)
{
    int ans=0;
    
    while (t)
    {
        ans+=tr[t];
        t-=low(t);
    }
    
    return ans;
}

void work1()
{
    int i;
    
    fo(i,1,n)
    if (d[i].s)
    change(d[i].x,d[i].s);
    else
    ans[d[i].id]-=find(d[i].x-1);
    
    memset(tr,0,sizeof(tr));
}

void work2(int l,int r)
{
    int i,mid=(l+r)/2;
    
    if (l==r) return;
    
    work2(l,mid);
    work2(mid+1,r);
    
    sort(D+l,D+r+1,cmp);
    
    fo(i,l,r)
    if (D[i].Id<=mid && D[i].s)
    change(D[i].y,D[i].s);
    else
    if (D[i].Id>mid && !D[i].s)
    ans[D[i].id]+=find(D[i].y-1);
    
    fo(i,l,r)
    if (D[i].Id<=mid && D[i].s)
    clear(D[i].y);
}

int main()
{
//  freopen("e.in","r",stdin);
    
    scanf("%d",&n);
    fo(i,1,n)
    {
        scanf("%d",&tp);
        
        switch (tp)
        {
            case 1:{
                scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
                
                ++sum;
                a[i].s=1;
                b[++tot]=a[i];
                break;
            }
            case 2:{
                scanf("%d",&j);
                
                --sum;
                a[i]=b[j];
                a[i].s=-1;
                break;
            }
            case 3:{
                scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
                
                a[i].id=++Tot;
                ans[Tot]=sum;
                break;
            }
        }
    }
    
//  ---
    
    len=0;
    fo(i,1,n)
    {
        c[++len]={a[i].x1,i};
        c[++len]={a[i].x2,-i};
    }
    sort(c+1,c+len+1,Cmp);
    j=0;
    fo(i,1,len)
    {
        j+=i==1 || c[i].s!=c[i-1].s;
        
        if (c[i].id>0)
        a[c[i].id].x1=j;
        else
        a[-c[i].id].x2=j;
    }
    
    len=0;
    fo(i,1,n)
    {
        c[++len]={a[i].y1,i};
        c[++len]={a[i].y2,-i};
    }
    sort(c+1,c+len+1,Cmp);
    j=0;
    fo(i,1,len)
    {
        j+=i==1 || c[i].s!=c[i-1].s;
        
        if (c[i].id>0)
        a[c[i].id].y1=j;
        else
        a[-c[i].id].y2=j;
    }
    
//  ---
    
    fo(i,1,n)
    if (a[i].s)
    d[i]={a[i].x2,a[i].s,0};
    else
    d[i]={a[i].x1,0,a[i].id};
    work1();
    
    fo(i,1,n)
    if (a[i].s)
    d[i]={200001-a[i].x1,a[i].s,0};
    else
    d[i]={200001-a[i].x2,0,a[i].id};
    work1();
    
    fo(i,1,n)
    if (a[i].s)
    d[i]={a[i].y2,a[i].s,0};
    else
    d[i]={a[i].y1,0,a[i].id};
    work1();
    
    fo(i,1,n)
    if (a[i].s)
    d[i]={200001-a[i].y1,a[i].s,0};
    else
    d[i]={200001-a[i].y2,0,a[i].id};
    work1();
    
//  ---
    
    fo(i,1,n)
    if (a[i].s)
    D[i]={a[i].x2,a[i].y2,a[i].s,0};
    else
    D[i]={a[i].x1,a[i].y1,0,a[i].id};
    fo(i,1,n)
    D[i].Id=i;
    work2(1,n);
    
    fo(i,1,n)
    if (a[i].s)
    D[i]={200001-a[i].x1,200001-a[i].y1,a[i].s,0};
    else
    D[i]={200001-a[i].x2,200001-a[i].y2,0,a[i].id};
    fo(i,1,n)
    D[i].Id=i;
    work2(1,n);
    
    fo(i,1,n)
    if (a[i].s)
    D[i]={a[i].x2,200001-a[i].y1,a[i].s,0};
    else
    D[i]={a[i].x1,200001-a[i].y2,0,a[i].id};
    fo(i,1,n)
    D[i].Id=i;
    work2(1,n);
    
    fo(i,1,n)
    if (a[i].s)
    D[i]={200001-a[i].x1,a[i].y2,a[i].s,0};
    else
    D[i]={200001-a[i].x2,a[i].y1,0,a[i].id};
    fo(i,1,n)
    D[i].Id=i;
    work2(1,n);
    
//  ---
    
    fo(i,1,Tot)
    printf("%d\n",ans[i]);
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!