• [考试反思]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

    思路积累:

    • 三分函数,根据含义或者打表发现单峰性质
    • 线段树
    • 贪心:线段覆盖问题,如何处理后效性
    • 差分:区间加减单点查询的优化
  • 相关阅读:
    windows安装nacos
    anki处理
    minikube安装net5
    在.net core中使用属性注入
    C# 使用MD5算法对密码进行加密
    c# 获取本机系统已经安装的打印机信息
    C# 比较两个datatable并找出修改差异的值
    打印机点击打印后无反应
    GUID转换成16位字符串或19位数据(确保唯一)
    RESTful
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11524104.html
Copyright © 2020-2023  润新知