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=2333K≡∑i=2333K((i mod 2333N mod 2333)∗(i div 2333N div 2333))(mod2333)
同理,我们按照 K div 2333 逐一分拆合并,可以得到下式:
∑i=0k(in)≡∑j=0k div 2333−1(jn div 2333)∗∑i=0n mod 2333(2333−1N 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;
}