打了计蒜客上的银川重现赛,总体感觉难度上确实比平时区域赛要低上一些。
这里补一下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]='