[考试反思]0914csp-s模拟测试43:破绽

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 }
View Code

思路积累:

  • 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 }
View Code

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 }
View Code

思路积累:

  • 三分函数,根据含义或者打表发现单峰性质
  • 线段树
  • 贪心:线段覆盖问题,如何处理后效性
  • 差分:区间加减单点查询的优化
原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11524104.html