T1会正解。爆int了,代码里一大堆long long但是有一个地方落了。-70分。
离考试结束还有19秒的时候发现手模样例爆负数了,没来得及改。
T2没想。打暴力了。然而实际很好想。。。早读5分钟就想出来了。可是考场上没好好想。。。
T3打的是正解,不知道哪错了,爆零。
关键经验:考场上如果不会MLE的话,#define int long long很稳!!!
要根据部分分一步一步想思路,不要嫌弃部分分少,因为它可能就是正解的钥匙。
单单这一场考试,总排名直接滚蛋到第9左右。
如果目标还高于省一的话,没有再失手任何一次的机会了。
细致。坚持。稳重。
T1:A
不难。记得开long long就行。
加和乘,那么最后一定可以表示为$ T=S×x+a*y $的形式,其中x是b的整次幂。
接下来把y表示为b进制,把每一位求和即为最优决策。
1 #include<cstdio> 2 long long min(long long a,long long b){return a<b?a:b;} 3 long long S,T,a,m,ans=1e18,mt; 4 int main(){ 5 scanf("%lld%lld%lld%lld",&S,&T,&a,&m); 6 if((T-S)%a==0)ans=(T-S)/a; 7 while(S<T/m){ 8 mt++;S*=m; 9 if((T-S)%a)continue; 10 long long et=mt,tms=(T-S)/a; 11 for(int i=1;i<=mt;++i)et+=tms%m,tms/=m; 12 ans=min(ans,et+tms); 13 } 14 printf("%lld ",ans); 15 }
思路积累:
- long long
- 出题人数据极其毒瘤
T2:B
好题。
和正解不一样,代码量与代码性能很好,但是代价是思维量很大。
我们可以把p质因数分解,得到$p=p_1^{t_1} imes p_2^{t_2} imes ... imes p_u^{t_u}$
然后我们对于u个相同但是p为$p_i^{t_i}$的子问题求解。
思想类似与CRT,根据乘法计数原理,答案相乘即为最后答案。
我们对于两个子问题,其中的每个方案都对应着一个序列,序列每个数都不超过$p_i^{t_i}$。
那么每次合并两个序列时,我们能唯一确定最后对于p的序列,类似与CRT思想,是一一对应的。
现在考虑子问题。
我们有性质,当gcd(a,p)==gcd(b,p)时,得到a和b的方案数相等。
那么,因为我们现在在考虑对于$p_i^{t_i}$的子问题,所以gcd一定是$p_i$的整次幂,或者0。
设dp[i][j][k]表示对于第i种质因子,已经选了j个数,目前是gcd是k-1次(如果k=0表示已经乘成了0)
考虑转移,0的情况特判,不然在模$p_i^{t_i}$的意义下次数是单调不减的。
0次可以转移到$0~{t_i}$次,1次可以转移到$1~{t_i}$次...
考虑转移的系数是多少。以${p_i==2,k==2}$为例。
0次可以转移到0次及以上的所有数,转移1份。
1次可以转移到1次及以上,转移目标少了一半,故转移的份数加倍.
而1次的数的数量恰好是0次的数的数量的1/2,但是转移的份数又是2倍,那么总系数还是没有变化。
同理可以推广到高次,转移系数全都相同。
现在在于如何求出系数,暴力搞一下其中任意一种情况就行,可以用欧拉函数,也可以简单容斥。
至于乘完后取模得0的情况,特殊处理即可。因为如果是0了以后一定都是0,所以不会转移出去。
只要暴力处理最后一层,用全部选法减去非0选法即可。
总复杂度$O((n+m) imes sumlimits_{i=1}^{u}t_i)$略低于O((n+m)log p)
1 #include<cstdio> 2 #define mod 1000000007 3 #define int long long 4 int pow(int b,int t,int a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;} 5 int p,n,m,ps[13],tms[13],dp[13][55][30],sum[13][55][30],cp,cs[13]; 6 main(){ 7 scanf("%lld%lld%lld",&n,&m,&p); 8 for(int i=2;i*i<=p;++i)if(p%i==0){ 9 ps[++cp]=i;cs[cp]=1; 10 while(p%i==0)p/=i,tms[cp]++,cs[cp]*=i; 11 cs[cp]=cs[cp]/i*(i-1); 12 } 13 if(p!=1)ps[++cp]=p,cs[cp]=p-1,tms[cp]=1; 14 for(int i=1;i<=cp;++i){ 15 for(int j=0;j<=tms[i];++j)dp[i][1][j]=1,sum[i][1][j]=j; 16 for(int j=2;j<=n;++j)for(int k=1;k<=tms[i];++k) 17 (dp[i][j][k]+=sum[i][j-1][k]*cs[i])%=mod, 18 sum[i][j][k]=(sum[i][j][k-1]+dp[i][j][k])%mod; 19 dp[i][n][0]=pow(cs[i]/(ps[i]-1)*ps[i],n); 20 int al=0,lim=cs[i]/(ps[i]-1),x=lim*ps[i]-1; 21 for(int k=tms[i];k;--k)(dp[i][n][0]+=mod-dp[i][n][k]*(x/lim-al)%mod)%=mod,al=x/lim,lim/=ps[i]; 22 } 23 for(int r=1;r<=m;++r){ 24 int q,ans=1;scanf("%lld",&q); 25 for(int i=1;i<=cp;++i){ 26 int req=q%(cs[i]/(ps[i]-1)*ps[i]),ccp=0; 27 if(req==0)goto re; 28 while(req%ps[i]==0)ccp++,req/=ps[i];ccp++; 29 re: (ans*=dp[i][n][ccp])%=mod; 30 } 31 printf("%lld ",ans); 32 } 33 }
T3:C
三分函数+贪心。
三分特殊加热器的次数,费用是个单峰函数。
然后就是线段覆盖问题,依次考虑每盆植物的mxr表示能覆盖i的区间的最大右端点是mxr[i]
每盆植物还需要p次的话,那么就对[i,mxr[i]]区间都进行p次就好。
操作是区间减,单点查询,可以用差分。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 #define int long long 5 int n,m,t,mxr[100005],w[100005],cf[100005],ans=12345678901234567ll; 6 int check(int mid){ 7 int fee=mid*t,tot=0; 8 for(int i=1;i<=n;++i)cf[i]=max(w[i]-mid,0ll)-max(w[i-1]-mid,0ll); 9 for(int i=1;i<=n;++i){ 10 tot+=cf[i]; 11 if(tot>0&&mxr[i]<i)return 12345678901234567ll; 12 if(tot>0)fee+=tot,cf[mxr[i]+1]+=tot,cf[i+1]-=tot; 13 } 14 ans=min(ans,fee); 15 return fee; 16 } 17 main(){//freopen("1.in","r",stdin); 18 scanf("%lld%lld%lld",&n,&m,&t); 19 for(int i=1;i<=n;++i)scanf("%lld",&w[i]); 20 for(int i=1,l,r;i<=m;++i)scanf("%lld%lld",&l,&r),mxr[l]=max(mxr[l],r); 21 int l=0,r=10000000; 22 for(int i=1;i<=n;++i)mxr[i]=max(mxr[i-1],mxr[i]); 23 while(l<r-2) 24 if(check(l+r>>1)<check((l+r>>1)+1))r=(l+r>>1)+1; 25 else l=l+r>>1; 26 check(l);check(l+1);check(l+2); 27 printf("%lld ",ans); 28 }
思路积累:
- 三分函数,根据含义或者打表发现单峰性质
- 线段树
- 贪心:线段覆盖问题,如何处理后效性
- 差分:区间加减单点查询的优化