2019icpc银川站 复现赛

这一生的挚爱 提交于 2019-12-06 07:07:49

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

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

  • 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\n",max(a1,a2));
 98         }
 99     }
100     return 0;
101 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!