ACM训练日记—5月16日

     省赛之后终于又更新博客了,这两个星期的作业考试真是折腾的我够呛,有一大堆题目没有整理,还是慢慢整理吧。

Codeforces 87C Interesting Game

     题意:一开始有一堆数量为n的石子,每次把其中的一堆石子分成任意堆,要求分成的堆数满足a[1]-a[2]=a[2]-a[3]=a[3]-a[4]......=a[k-1]-a[k]=1,其中k>=2,如果先手能赢,输出先手第一次分石子应分的最小堆数,否则输出-1.

       这道题我找规律做的并不过。题解其实就是sg函数打表还是要好好在看看博弈了。

来自:https://blog.csdn.net/i1020/article/details/79824567

【思路】sg函数打表,求出其子状态的sg值。首先从3....n枚举石子数,内层再枚举当前可能分的堆数;假设当前分了m堆,这m堆中石子数量最少的为x个,又知当前m堆石子为等差数列,最小项为x,则可得当前m堆的石子总数量为(x-1)*m+(m*(m+1)/2);所以用当前总共的石子数量i-m*(m+1)/2的结果一定为m的倍数。然后通过其子状态的sg值异或得到当前状态的sg值即可。

const int N = 1e5+10;
int n,sg[N],mex[N];
int main()
{
    scanf("%d",&n);
    int ans = -1;
    int cnt = 1;
    for(int i = 3; i <= n; i ++)
    {
        for(int m=2;;m++)
        {
            int r=i-m*(m+1)/2;
            if(r<0) break;
            if(r%m) continue;
            int g=0;  //g表示其子状态的异或和
            for(int j=1;j<=m;j++) g^=sg[r/m+j];
            if(!g && i==n && ans < 0) ans = m;
            mex[g] = cnt;
        }
        for(int j=0;;j++)
        {
            if(mex[j]!=cnt)
            {
                sg[i]=j;
                cnt++;
                break;
            }
        }
    }
    printf("%d\n",ans);
    return 0;

}

Gym - 101532C

题意:给出一个数列,求任意两个数相加(ai+aj)%1e9+7求最大。

思路:我的思路是因为题目说ai<=1e9所以,ai+aj<=2e9,那么将数列中的数排下序依次拿出,那么ai+x<=1e9+7的数,和ai+x<=2e9,照两个最接近的数比最大值。相当于两个峰值(最多存在两个峰值)。还是看代码吧。(注意要判断二分得到的值是不是ai本身,否则要退一位取)

代码:

const ll mod=1e9+7;
struct node
{
    ll val;
    ll id;
}a[100005];
bool cmp(node s,node t)
{
    if(s.val==t.val) return s.id<t.id;
    return s.val<t.val;
}
ll n;
ll ans[100005];
ll search(ll begin,ll end,ll e)
{
    ll mid,left=begin,right=end;
    while(left<=right)
    {
        mid=(left+right)>>1;
        if(a[mid].val>e) right=mid-1;
        else left=mid + 1;
    }
    return right;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i].val);
            a[i].id=i;
        }
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<=n;i++)
        {
            ll t=search(1,n,mod-a[i].val-1);
            if(a[i].id==a[t].id) t--;
            //cout<<t<<endl;
            if(t!=0)
            {
                ans[a[i].id]=(a[t].val+a[i].val)%mod;
                //cout<<ans[a[i].id]<<endl;
            }
            else ans[a[i].id]=0;
            //cout<<ans[a[i].id]<<endl;
            t=search(1,n,2*mod-a[i].val-1);
            if(a[i].id==a[t].id) t--;
            ans[a[i].id]=max(ans[a[i].id],(a[t].val+a[i].val)%mod);
        }
        for(int i=1;i<=n;i++) cout<<ans[i]<<" ";cout<<endl;
    }

}

Gym - 101532J

题意:给出一个数列(a1,a2...an),求a1+a2+...an+(a1a2)+(a1a3)+....(a1a2a3...an)。

其实就是个组合数学公式(a1+1)(a2+1)...(an+1)。用递推式写出来就行了。

const ll mod=1e9+7;
ll a[100005];
ll dp[100005];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ll n;
        scanf("%lld",&n);
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
        dp[1]=a[1]%mod;
        for(int i=2;i<=n;i++)
        {
            dp[i]=(dp[i-1]+((dp[i-1]*a[i])%mod+a[i])%mod)%mod;
        }
        cout<<dp[n]<<endl;
    }

}

     

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值