Defuse the Bombs

听说是公司面试题,答案满足二分性质,直接二分check(对于每个ai***桶在x的时间段,要么有ti时间一直在降低,x-ti时间在保持不变.贪心让不变的时间尽可能少。)
本题坑点:二分右边界设置1e10(设置太大直接爆long long WA)

#include<bits/stdc++.h>
using namespace std;


const int maxn=2e6+10;

typedef long long ll;

ll a[maxn],b[maxn];
ll n;
bool check( ll x )
{
    ll t1=0;
    for( int i=1;i<=n;i++ )
    {
        if( a[i]<x ) t1+=x-a[i];    
    }
    return t1<=x;
}

int main()
{
//        freopen("1.in","r",stdin);
//  freopen("1.out","w",stdout);
    ll t;
    scanf("%lld",&t);
    int cas=1;
    while( t-- )
    {
        scanf("%d",&n);
        ll l=0,r=1e10;
        for( int i=1;i<=n;i++ ) scanf("%lld",&a[i]);
//        sort(a+1,a+1+n);

        ll ans=0;
        while( l<=r )
        {
            ll mid=l+r>>1;
            if( check(mid) ) 
            {
                ans=mid,l=mid+1;
            }
            else r=mid-1;
        }
        printf("Case #%d: %lld\n",cas++,ans+1);
    }
}

Game of Cards

博弈没思路就上sg,三维sg分别记录0,1,2的个数。
看着sg表推规律,具体看代码~~.

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;


const int maxn=50+10;

int sg[maxn][maxn][maxn];

void init()
{
    sg[0][0][1]=0;
    sg[0][1][0]=0;
    sg[1][0][0]=0;
    sg[0][0][0]=0;

    for( int i=0;i<=maxn-1;i++ )
    {
        for( int j=0;j<=maxn-1;j++ )
        {
            for( int k=0;k<=maxn-1;k++ )
            {
                bool vis[100]={false};
                if( i>=1 ) vis[sg[i-1][j][k]]=true;
                if( j>1 ) vis[sg[i][j-2][k+1]]=true;
                if( j && k ) vis[sg[i][j-1][k-1]]=true;
                int t=0;
                   while( vis[t] ) t++;
                sg[i][j][k]=t;
            }
        }
    }


    for( int i=0;i<=20;i++ )
    {
        for( int j=0;j<=20;j++ )
        {
            for( int k=0;k<=2;k++ )// k<=2 因为 k>=2 的sg值都相同 
            {
                cout<<i<<" "<<j<<" "<<k<<" "<<sg[i][j][k]<<"\n";
            }
        }
    }


}


int main() 
{
//    init(); //此打表 默认0在任何时候都可以减一 
    int t,cas=1;
    scanf("%d",&t);
    while( t-- ) 
    {
        ll a,b,c,d;
        scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
        printf("Case #%d: ",cas++);
        if( a+b+c+d<2 ) 
        {
            printf("Horse\n");
            continue;
        }
        if( b==0 && c==0 && d==0 ) 
        {
            if( a&1 ) puts("Horse");
            else puts("Rabbit");
            continue;
        }
        int f=1;
        if( a%2==0 ) 
        {
            if( b%3==0 ) f=0; 
            else if( b%3==1 && c==0 ) f=0; 
        }else   
        {
            if( b%3==1 && c>0 ) f=0;
            else if( b%3==2 && c<=1 ) f=0; 
        }
        if( f ) puts("Rabbit");
        else puts("Horse");
    }
    return 0;
}

Joy of Handcraft

稍微算一下用线段树暴力区间更新和单点查询,复杂度为O(nlognlogn)可以过。直接码。

#include<bits/stdc++.h>
using namespace std;
#define ls cur<<1
#define rs cur<<1|1
#define lowbit(x) x&(-x)

const int maxn=1e6+10;
const int inf=0x3f3f3f3f;
typedef long long ll;

ll lazy[maxn],mx[maxn],sum[maxn];
ll a[maxn],b[maxn];

void pushup( int cur )
{
    mx[cur]=max(mx[ls],mx[rs]);
}

void pushdown( int cur )
{
    if( lazy[cur]==0 ) return;
    mx[ls]=max(mx[ls],lazy[cur]);lazy[ls]=max(lazy[cur],lazy[ls]);
    mx[rs]=max(mx[rs],lazy[cur]);lazy[rs]=max(lazy[cur],lazy[rs]);
    lazy[cur]=0;
}

void build( int cur,int l,int r )
{
    lazy[cur]=0;
    if( l==r )
    {
        mx[cur]=0;
        return;
    }
    int mid=l+r>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    pushup(cur);
}

void update( int cur,int l,int r,int ql,int qr,ll c )
{
    if( ql<=l && r<=qr )
    {
        mx[cur]=max(c,mx[cur]);
        lazy[cur]=max(c,lazy[cur]);
        return;
    }
    pushdown(cur);
    int mid=l+r>>1;
    if( ql<=mid ) update(ls,l,mid,ql,qr,c);
    if( qr>mid ) update(rs,mid+1,r,ql,qr,c);
    pushup(cur);
}

ll query( int cur,int l,int r,int ql,int qr )
{

    if( ql<=l && r<=qr ) return mx[cur];
    pushdown(cur);
    ll res=-1e18;
    int mid=l+r>>1;
    if( ql<=mid ) res=max(res, query(ls,l,mid,ql,qr) );
    if( qr>mid ) res=max( res , query(rs,mid+1,r,ql,qr) );
    return res;
}

int mp[100005];

int main()
{
//        freopen("1.in","r",stdin);
//  freopen("1.out","w",stdout);
    int t,cas=1;
    scanf("%d",&t);
    while( t-- )
    {

        int n,m;
        scanf("%d%d",&n,&m);
        build(1,1,m);
        for( int i=1;i<=m;i++ ) mp[i]=0;
        for( int i=1;i<=n;i++ )
        {
            int ti,xi;
            scanf("%d%d",&ti,&xi);
            if( ti>=m ) ti=m;
            mp[ti]=max(mp[ti],xi);
        }
        for( int i=1;i<=m;i++ )
        {
            if( mp[i] )
            {
                int j;
                for( j=i;j<=m;j+=2*i )
                {
                    update(1,1,m,j-i+1,j,mp[i]);
                }
                if( j-i+1<=m )
                {
                    update(1,1,m,j-i+1,m,mp[i]);
                }
            }
        }
        printf("Case #%d: ",cas++);
        for( int i=1;i<=m;i++ ) 
        {
            printf("%d",query(1,1,m,i,i));
            if( i==m )puts("");
            else printf(" ");
        }

    }
}

Knowledge is Power

这道题很多做法是找规律,我是直接暴力分两个数或者三个数,直接搜更新。

#include<bits/stdc++.h>
using namespace std;


const int maxn=2e6+10;

typedef long long ll;

ll a[maxn],b[maxn];

int main()
{
    a[2]=-1,a[3]=-1,a[4]=-1,a[5]=1,a[6]=-1,a[7]=1;
    int n;
    int t,cas=1;
    scanf("%d",&t);
    while( t-- )
    {
        scanf("%d",&n);
        if( n<=7 ) printf("Case #%d: %d\n",cas++,a[n]);
        else
        {
            if( n&1 )
            {
                printf("Case #%d: 1\n",cas++);
            }
            else
            {
                if( (n/2)%2==0 )
                {
                    printf("Case #%d: 2\n",cas++);
                }
                else
                {
                    int ans=1e9;
                    for( int i=max(n/2-5,2);i<=min(n/2+5,n-2);i++ )
                    {
                        if( __gcd(n,n-i)==1 ) ans=min( ans,abs(n-2*i) );
                    }
                    int l1=max(n/3-5,2),r1=min(n/3+5,n-4);
                    int l2=max(n/3-5,2),r2=min(n/3+5,n-4);
                    for( int i=max(n/3-5,2);i<=min(n/3+5,n-4);i++ )
                    {
                        for( int j=max(n/3-5,2);i+j<=n-2 && j<=min(n/3+5,n-4);j++ )
                        {
                            int d=n-i-j;
                            if( __gcd(i,j)==1 && __gcd(i,d)==1 && __gcd(j,d)==1 )
                            {
                                int c1=max(i,max(d,j));
                                int c2=min(i,min(d,j));
                                ans=min(ans,abs(c2-c1));
                            }
                        }
                    }
                    if( ans==1e9 ) ans=-1;
                    printf("Case #%d: %d\n",cas++,ans);
                }
            }
        }
    }
}
/*
1
8275722
*/ 

Lottery

参考博客
https://blog.csdn.net/weixin_44216117/article/details/109545197

本题计算方法肯定类似二进制。如果有k个位置可以填1那么不同的数字就是图片说明 个.

然后考虑给定的若干个图片说明 ,2个图片说明可以变成一个图片说明 ,3个图片说明 可以组合成1个图片说明和1个图片说明。并且如果对于位置k只有2个图片说明 并且高一位图片说明 的个数为0,把当前这一位组合成图片说明 或者就保留成2个图片说明 对答案的贡献都是乘2,所以我们只有当个数大于2的时候才进行进位组合。

然后我们从小到大枚举位数,累加每位的个数,按上述规则进位,可以得到一段一段连续的非零数字串。例如:1,2,1,1,2.为一段连续的二进制每位的个数。首先可以表示图片说明 种数字,然后根据规律(将连续非零位置的数字减去1的获得的二进制数就是组合可以多出这个二进制表示的个数),获得图片说明 ,那么答案计算为:图片说明 。这个是这一段能表示的数的答案,将每一个这样的段结果乘起来就是最终答案。(规律我还不会证明

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int maxn=2e5+10;
const int mod=1e9+7;

struct node{
    ll a,x;
    bool operator<(const node A) const {
        return a < A.a;//按次方排序
    }
}p[maxn];
// 对于每个二进制数 

int main()
{
    int t,cas=1;
    scanf("%d",&t);
    while( t-- )
    {
        int n;scanf("%d",&n);
        for( int i=0;i<n;i++ )
        {
            scanf("%d%d",&p[i].a,&p[i].x);
        }        
        sort(p,p+n);
        ll sum=1,now=0,res=1,idx=0,tmp=0,add=0;
        while( true )
        {
            if( p[idx] .a==now ) tmp+=p[idx++].x;
            if( idx!=n && tmp==0 )
            {
                sum=(sum+add)%mod;
                res=res*sum%mod;
                sum=1,add=0;
                tmp=p[idx].x;
                now=p[idx++].a;
            }
            if( idx==n && tmp==0 )
            {
                sum=(sum+add)%mod;
                res=res*sum%mod;
                break;
            }
            if( tmp )
            {
                if( tmp%2==0 ) add=(add+sum)%mod;
                sum=sum*2%mod;
                now++;
                tmp=(tmp-1)>>1;
            }
        }
        printf("Case #%d: %lld\n",cas++,res);
    }
}