• 2019icpc银川站 复现赛


    打了计蒜客上的银川重现赛,总体感觉难度上确实比平时区域赛要低上一些。

    这里补一下F题和G题的思路和代码。

    upd:I题也补了,理解差不多都在注释里。

    • F题

           做法,玩一下n=10的样例就出来啦!

      解释:显然a^x的反函数为logax,我们先固定外层的求和的a,然后看内层求和的b,b从a开始加到n,注意到对于后半个向上取整的logba,b>=a,所以始终都是1,而对于前半个式子,只有当b经过a^i时才增加,举个例子就是log22~log23向下取整都为1,log24~log27向下取整都为2,log28~log210都为3.

    对于n=10的样例,a=2就可以这样玩出来,在玩a=3,同理,b从3~10的过程中,9和10的时候出来2。

    而对于4和4以后的值,我们发现后面求和的值都是n-i+1个1,就是从i到n中有多少个数,这部分我们就可以用公式算。咋算呢?

    Σi(n-i+1),显然 i 从sqrt(n)+1到n,把这个式子拆开来,就可以得到公式,此处注意 12+22+……+n2=n*(n+1)*(2n+1)/6;

    至此,我们就可以发现规律了!n最大到1e12,我们就可以对前sqrt(n)个数暴力的去算。后面部分的完美地去用公式算。

    不过比赛的时候,取模写炸了,导致10几分钟就推出来的结论,爆炸搞了2个小时,取模要每步取模,由于这里的n本身就很大,每个数本身都要取模,而更重要的是对于除法,取模意义下要用逆元来算,所以就用到了快速幂来求除法逆元。主要是这里除法经常炸,亏我对拍debug了半天。

    代码:

     1 #include <bits/stdc++.h>
     2 #define debug(x) cout << #x << ": " << x << endl
     3 using namespace std;
     4 typedef long long ll;
     5 const int MAXN=2e5+7;
     6 const int INF=0x3f3f3f3f;
     7 const int MOD=998244353;
     8 
     9 
    10 ll quick(ll x,ll n)  //快速幂 x^n
    11 {
    12     ll res=1;
    13     while(n)
    14     {
    15         if(n&1) res=(res*x)%MOD;
    16         x=(x*x)%MOD;
    17         n>>=1;
    18     }
    19     return res;
    20 }
    21 
    22 ll inv(ll a)   //逆元  费马小定理,要求 a,mod互素
    23 {
    24     return quick(a,MOD-2);
    25 }
    26 
    27 ll i2sum(ll i)
    28 {
    29     return (((i%MOD)*((i+1)%MOD))%MOD*(((2*i)%MOD+1)%MOD))%MOD*inv(6)%MOD;
    30 }
    31 
    32 
    33 int main()
    34 {
    35     ios::sync_with_stdio(false);
    36     cin.tie(0);
    37     ll n;
    38     cin>>n;
    39     ll ans=0;
    40     ll k=(ll)sqrt(n)+1;
    41     //debug(k);
    42     for(ll i=2;i<k;++i)
    43     {
    44         ll t=i;
    45         ll q=0;
    46         while(t<=n)
    47         {
    48             q=(q+n-t+1)%MOD;
    49             t*=i;
    50         }
    51         ans=(ans+(q%MOD)*(i%MOD)%MOD)%MOD;
    52         //debug(ans);
    53     }
    54     //debug(ans);
    55     ans=(ans+(((((n+1)%MOD)*((n-k+1)%MOD))%MOD*(((k+n)%MOD)*inv(2)%MOD)%MOD)%MOD+i2sum(k-1)-i2sum(n)+MOD)%MOD)%MOD;
    56    // debug(ans);
    57     //ll t=i2sum(n);
    58     //debug(t);
    59     cout<<ans<<endl;
    60     return 0;
    61 }
    62 //200 1366404
    63 //1000 167464908
    64 //10000 36893337
    65 //100000 384927495
    66 //1000000 960529847
    67 //10000000 679483439
    68 //100000000 498142384

    debug和对拍数据没删,也可以对照一下。

    • G题

    g题一开始看题目看傻了,p是啥完全不知道,后来和队长讨论了一下,结合样例一看,就对上感觉了。

    因为操作就是乘2到10之间的一个数,很显然pm | n 且  不pm+1 | n  的m 就是你已经对p乘的操作,需要对照样例感觉一下。

    然后维护四棵 区间加法,维护最大值的线段树了。

    然后对于2~10的数你可以写if else ,也可以像我这样写,每次差几个log级update的操作问题不大。

    然后这两天的数据结构和计算几何题,告诉我这类题一定要scanf,printf,开优化的cin也不行!!!

    然后就没啦!(cry!

      1 #include <bits/stdc++.h>
      2 #define debug(x) cout << #x << ": " << x << endl
      3 #define lson (rt<<1)
      4 #define rson (rt<<1|1)
      5 
      6 using namespace std;
      7 typedef long long ll;
      8 const int MAXN=2e5+7;
      9 const int INF=0x3f3f3f3f;
     10 const int MOD=1e9+7;
     11 int prime[4]={2,3,5,7};
     12 
     13 struct tree
     14 {
     15     int seg[MAXN<<2];
     16     int lazy[MAXN<<2];
     17     inline void pushup(int rt){ seg[rt]=max(seg[lson],seg[rson]); }
     18     inline void pushdown(int rt)
     19     {
     20         if(lazy[rt])
     21         {
     22             lazy[lson]+=lazy[rt];
     23             lazy[rson]+=lazy[rt];
     24             seg[lson]+=lazy[rt];
     25             seg[rson]+=lazy[rt];
     26             lazy[rt]=0;
     27         }
     28     }
     29     void build(int l,int r,int rt)
     30     {
     31         seg[rt]=lazy[rt]=0;
     32         if(l==r) {seg[rt]=0;return;}
     33         int m=(l+r)>>1;
     34         build(l,m,lson);
     35         build(m+1,r,rson);
     36         pushup(rt);
     37     }
     38 
     39     void update(int l,int r,int rt,int ql,int qr,ll x)
     40     {
     41         if(ql<=l && r<=qr) {seg[rt]+=x;lazy[rt]+=x;return;}
     42         pushdown(rt);
     43         int m=(l+r)>>1;
     44         if(ql<=m) update(l,m,lson,ql,qr,x);
     45         if(qr>m) update(m+1,r,rson,ql,qr,x);
     46         pushup(rt);
     47     }
     48 
     49     int query(int l,int r,int rt,int ql,int qr)
     50     {
     51         if(ql<=l && r<=qr) return seg[rt];
     52         pushdown(rt);
     53         int m=(l+r)>>1;
     54         int ans=-INF;
     55         if(ql<=m) ans=max(ans,query(l,m,lson,ql,qr));
     56         if(qr>m) ans=max(ans,query(m+1,r,rson,ql,qr));
     57         return ans;
     58     }
     59 }t[4];
     60 
     61 int main()
     62 {
     63     int n,q;
     64     scanf("%d%d",&n,&q);
     65     //for(int i=0;i<4;++i) t[i].build(1,n,1);
     66     while(q--)
     67     {
     68         char s[10];
     69         scanf("%s",s);
     70         int a,b,x;
     71         if(s[1]=='U')
     72         {
     73             scanf("%d%d%d",&a,&b,&x);
     74             for(int i=0;i<4;++i)
     75             {
     76                 int tt=0;
     77                 while(x%prime[i]==0)
     78                 {
     79                     x/=prime[i];
     80                     tt++;
     81                 }
     82                 //debug(tt);
     83                 if(tt!=0) t[i].update(1,n,1,a,b,tt);
     84                 if(x==1) break;
     85             }
     86         }
     87         else
     88         {
     89             scanf("%d%d",&a,&b);
     90             int ans[4];
     91             for(int i=0;i<4;++i)
     92             {
     93                 ans[i]=t[i].query(1,n,1,a,b);
     94                 //debug(ans[i]);
     95             }
     96             int a1=max(ans[0],ans[1]),a2=max(ans[2],ans[3]);
     97             printf("ANSWER %d
    ",max(a1,a2));
     98         }
     99     }
    100     return 0;
    101 }
    • I题

    2~62任意进制的转换,poj1220

    代码来源于大神,看了有些时间才差不多理解。

    原来的代码是利用字符ASCII码直接映射的,我自己写的建立了两个互相的映射map,感觉也挺好用的。

    转换的核心过程见注释代码。

     1 #include <bits/stdc++.h>
     2 #define debug(x) cout<< # x <<": "<<x<<endl
     3 using namespace std;
     4 const int MAXN=1e3+7;
     5 
     6 map<char,int> mp;
     7 map<int,char> mp2;
     8 
     9 void init()
    10 {
    11     int k=0;
    12     char c;
    13     for(int i=48;i<58;++i) //0~9
    14     {
    15         c=i;
    16         mp2[k]=c;
    17         mp[c]=k++;
    18     }
    19     for(int i=65;i<65+26;++i) //A~Z
    20     {
    21         c=i;
    22         mp2[k]=c;
    23         mp[c]=k++;
    24     }
    25     for(int i=97;i<97+26;++i)  //a~z
    26     {
    27         c=i;
    28         mp2[k]=c;
    29         mp[c]=k++;
    30     }
    31 }
    32 int n,m;
    33 char s[MAXN],ans[MAXN];
    34 int t[MAXN],a[MAXN];
    35 
    36 void solve()
    37 {
    38     int len=strlen(s),k=0;
    39     for(int i=len-1;i>=0;--i)
    40     {
    41         t[len-i-1]=mp[s[i]];  //倒置 得到每位的值 下标0表示低位
    42     }
    43     for(k;len;)  //模拟 除m取余 的过程  一次得到低位的一个数
    44     {
    45         for(int i=len-1;i>=1;--i)  //
    46         {
    47             t[i-1]+=t[i]%m*n;
    48             t[i]/=m;
    49         }
    50         a[k++]=t[0]%m;
    51         t[0]/=m;
    52         while(len && !t[len-1])  //当前高位已为0,可以减少总位数
    53             len--;
    54     }
    55     ans[k]='';
    56     for(int i=0;i<k;++i)
    57     {
    58         ans[k-i-1]=mp2[a[i]];  //数是从下标0开始的,需要倒置
    59     }
    60 }
    61 int main()
    62 {
    63     ios::sync_with_stdio(false);
    64     cin.tie(0);
    65     init();
    66     cin>>n>>m;
    67     cin>>s;
    68     solve();
    69     cout<<ans<<endl;
    70     return 0;
    71 }
  • 相关阅读:
    Mysql蠕虫复制
    Mysql中如何开启慢查询功能?
    线程的状态以及状态切换
    Java的Unsafe类
    Spring 获取jar内外文件的方式
    RocketMQ学习
    volatile的理解
    快速排序
    JVM的发展史
    nginx安装配置
  • 原文地址:https://www.cnblogs.com/Zzqf/p/11968351.html
Copyright © 2020-2023  润新知