zoukankan      html  css  js  c++  java
  • 【SPOJ】Transposing is even more fun!

    题意:

    给出a、b 表示按先行后列的方式储存矩阵 现在要将其转置 可以交换两个点的位置 求最小操作次数

    题解:

    储存可以将其视为拉成一条链 设a=5、b=2 则在链上坐标用2^***(a,b)表示为(xxxxxyy) 转置后为(yyxxxxx)

    这时将其视为另一个点的坐标 继续转置为(xxyyxxx)... 直到再变成(xxxxxyy)这样每次循环可以节省1次转置 所以ans=2^(a+b)-k k为循环的个数
    k的计算:右移b位 右移b*2位 右移b*3位... 构成了一个置换群 置换个数为(a+b)/***(a,b)

    因为它是循环的 所以向右移bx位 可视为右移bx%(a+b)位 设bx=z(mod (a+b))

    该方程有解条件为***(b,(a+b))|z -> ***(a,b)|z 所以z为***(a,b)的倍数

    k的值可理解为将长度为(a+b)/***(a,b)的串 染成2^***(a,b)种颜色(循环移动视为同种方案) 的方案数

    既为poj2154的题目


    因为spoj会卡常数 这题很容易TLE 我做了几个优化:

    1.记忆化欧拉函数 将算过的欧拉函数存下来 下次直接用

    2.预处理幂 可以发现这题要用的幂都是2^x 可以直接预处理出来

    3.dfs n的因数 枚举m的因数会浪费很多时间 可以先算出n的质因数 在通过dfs算出其因数

    4.尽量不要用long long 在会超int的地方强制转换一下就行

    这题时限是8s 我跑了4.2s 目测前面T了十几次

    代码:

     1 #include <cstdio>
     2 #define _(x) static_cast<long long>(x)
     3 const int mo=1000003;
     4 typedef int ll;
     5 ll t,a,b,n,m,g,phii[1000001],primer[1001],np,flag[1001],pow[1000001],ans,p[1001],nn;
     6 void makep(ll t){
     7      for (int i=1;i<=np && t>1 && primer[i]*primer[i]<=t;i++)
     8      if (t%primer[i]==0){
     9                          p[++nn]=primer[i];
    10                          while (t%primer[i]==0) t/=primer[i];
    11      }
    12      if (t>1) p[++nn]=t;
    13 }
    14 ll phi(ll t){
    15           ll out=1,tt=t;
    16           if (phii[t]) return phii[t];
    17           for (int i=1;i<=np && t>1 && primer[i]*primer[i]<=t;i++)
    18           if (t%primer[i]==0){
    19                               t/=primer[i];
    20                               out=_(out)*_((primer[i]-1))%mo;
    21                               while (t%primer[i]==0) t/=primer[i],out=_(out)*_(primer[i])%mo;
    22           }
    23           if (t>1) out=_(out)*_((t-1))%mo;
    24           return phii[tt]=out;
    25 }
    26 void dfs(ll now,ll sum){
    27      if (now>nn){
    28                  ans=(ans+_(phi(n/sum))*_(pow[sum*g]))%mo;
    29                  return;
    30      }
    31      for (ll i=1;n%i==0;i*=p[now]) dfs(now+1,sum*i);
    32 }
    33 void extgcd(ll a,ll b,ll &x,ll &y){
    34      if (!b) x=1,y=0;
    35      else{
    36           extgcd(b,a%b,x,y);
    37           ll t=x;
    38           x=y;
    39           y=t-a/b*y;
    40      }
    41 }
    42 ll gcd(ll a,ll b){
    43           while (b) b^=a^=b^=a%=b;
    44           return a;
    45 }
    46 ll work(){
    47           if (!a || !b) return 0;
    48           ll x,y;
    49           g=gcd(a,b);
    50           n=(a+b)/g;
    51           nn=ans=0;
    52           makep(n);
    53           dfs(1,1);
    54           extgcd(n,mo,x,y);
    55           x=(x%mo+mo)%mo;
    56           ans=(_(ans)*_(x))%mo;
    57           return ((pow[a+b]-ans)%mo+mo)%mo;
    58 }
    59 void makepr(){
    60      for (int i=2;i<=1000;i++){
    61          if (!flag[i]) primer[++np]=i;
    62          for (int j=1;j<=np && primer[j]*i<=1000;j++){
    63              flag[primer[j]*i]=1;
    64              if (i%primer[j]==0) break;
    65          }
    66      }
    67      pow[0]=1;
    68      for (int i=1;i<=1000000;i++) pow[i]=(pow[i-1]*2)%mo;
    69 }
    70 int main(){
    71     freopen("spoj442.in","r",stdin);
    72     freopen("spoj442.out","w",stdout);
    73     scanf("%d
    ",&t);
    74     makepr();
    75     while (t--){
    76           if (t==0){
    77                   t=0;
    78           }
    79           scanf("%d%d
    ",&a,&b);
    80           printf("%d
    ",work());
    81     }
    82     fclose(stdin);
    83     fclose(stdout);
    84 }
    View Code
  • 相关阅读:
    ABAP POH和POV事件中 获得屏幕字段的值
    SAP 发送邮件 面向对象
    SAP文件的上传下载 SMW0,二进制文件
    SAP smartform 实现打印条形码
    SAP GB01替代 程序:RGUGBR00
    SAP问题【转载】
    物料库存确定组
    SAP ECC EHP7 RFC 发布成WebService
    NUMBER_GET_NEXT 获取编号 遇到关于按年度编号的问题
    SAP 参照sto订单创建外向交货BAPI
  • 原文地址:https://www.cnblogs.com/g-word/p/3691759.html
Copyright © 2011-2022 走看看