SHOI2015大考Day1解题报告

3 篇文章 0 订阅
2 篇文章 0 订阅

Day1 T1 自动刷题机

题面

做法

打表可以注意到存在不严格单调性,即N越大,题数K只可能相等或更小。注意到答案的正确性在O(N)的范围内可以检验,我们即采用二分答案的做法完成此题。注意解的存在性问题。

#include <stdio.h>
#include <stdlib.h>
using namespace std;
long long L,l[100001],K;
int Judge ( long long Ans )
 {
    long long cnt=0,ac=0;
    for ( int i=1;i<=L;i++)
     {
        if(-l[i]>=cnt) cnt=0;
        else cnt+=l[i];
        if(cnt>=Ans) cnt=0,ac++;
      }
    if(ac>K) return 1;
    else if(ac==K) return 0;
    else return -1;
 }
long long binary_search1( long long l , long long r )
 {
    if(l>r) 
       {
          if(Judge(l)==0)  return l;
          else return -1;
       }
    long long mid=(l+r)>>1;
    short f=Judge(mid);
    if(f==1) return binary_search1(mid+1,r);
    else return binary_search1(l,mid-1);
 }
long long binary_search2( long long l , long long r )
 {
    if(l>r) 
       {
          if(Judge(r)==0)  return r;
          else return -1;
       }
    long long mid=(l+r)>>1;
    short f=Judge(mid);
    if(f!=-1) return binary_search2(mid+1,r);
    else return binary_search2(l,mid-1);
 }
int main() 
 {
       long long s=0;
       scanf("%lld%lld",&L,&K);
       for ( int i=1;i<=L;i++)
         {
           scanf("%lld",l+i);
           if(l[i]>0) s+=l[i];
        }
       long long Ans1=binary_search1(1,s);
       long long Ans2=binary_search2(1,s);
       if(Ans1==-1||Ans2==-1) printf("%d\n",-1);
       else printf("%lld %lld\n",Ans1,Ans2);
 }

Day1 T2 脑洞治疗仪

题面

做法

Day1 T3 超能粒子炮·改

题面

做法

本题是数论中Lucas定理的直接应用。Lucas定理说明了这样一个事实:

(sp+qtp+r)(st)(qr)(mod p)

那么对于
(kn) mod 2333
, 一定有
(kn)  (k div 2333n div 2333) (k mod 2333n mod 2333)(mod 2333)

我们将这个结论定义为推论1。那么注意到 k div 2333 的特殊性质,即它在 [0,2333) 区间内都是0,可以推得结论2:
i=0k(in)i=0k(i mod 2333n mod 2333)(0n div 2333)(mod2333)

对于 [2333,+) ,即有
i=2333Ki=2333K((i mod 2333N mod 2333)(i div 2333N div 2333))(mod2333)

同理,我们按照 K div 2333 逐一分拆合并,可以得到下式:
i=0k(in)j=0k div 23331(jn div 2333)i=0n mod 2333(23331N mod 2333)+(K div 2333N div 2333)j=0k mod 2333(jN mod 2333)

注意到这个式子中,子问题的结构和原问题相同,那么对这个子问题应用这个方法,问题即可解决。复杂度O(跑得过),找天证明一下试一试。

#include <stdio.h> 

#define MOD 2333

int C[MOD][MOD],sum[MOD][MOD];

int Lucas( long long N, long long K )

 {

    if(N<K||K<0) return 0;

    if(N<MOD&&K<MOD) return C[N][K];

    return Lucas(N/MOD,K/MOD)*C[N%MOD][K%MOD]%MOD;

 }

int cal_Ans( long long N , long long K )

 {

    if(K<0) return 0;

    else return (cal_Ans(N/MOD,K/MOD-1)*sum[N%MOD][MOD-1]%MOD+Lucas(N/MOD,K/MOD)*sum[N%MOD][K%MOD]%MOD)%MOD;

 }

void init() 

 {

    C[0][0]=sum[0][0]=1;

    for ( int i=1;i<MOD;i++)

       sum[0][i]=1;

    for ( int i=1;i<MOD;i++)

      sum[i][0]=C[i][0]=1; 

    for ( int i=1;i<MOD;i++)

       for ( int j=1;j<=i;j++) 

         C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;

    for ( int i=1;i<MOD;i++)

       for ( int j=1;j<MOD;j++)

         sum[i][j]=(sum[i][j-1]+C[i][j])%MOD;

 }

long long IN()

 {

     char ch=getchar();

     long long Ans=0;

     while(ch>'9'||ch<'0') ch=getchar();

     while(ch>='0'&&ch<='9')

      {

        Ans=Ans*10+ch-'0';

        ch=getchar();

       }

    return Ans;

 }

int main()

 {

    init();

    int T;

    long long N,K;

    scanf("%d",&T);

    for (;T>0;T--:)
      {
          N=IN(),K=IN();
          printf("%d\n",cal_Ans(N,K));
       }
    return 0;
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值