CF Round701-div2(CF1485)
题意:给出两个数,a和b,有两种操作,一种是a/b(计算机整除,只保留整数位),另一种是b+1,求最少通过多少次操作可以使得a==0。
题解:
- BFS。
- (UPD:2021-02-13-17:14)可以得出对于每一步的操作,先增加b,再去除,整体会比先除在增加更优,因为 a/b > a/(b+1)。solve2()即为30ms写法。
- (UPD:2021-02-15-00:30)通过观察可以发现,solve2()中的内层循环,其实是可以通过计算对数直接获得,不需要一个一个除。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define rep(i,a,n) for (int i=a;i<n;i++) 4 #define mp make_pair 5 #define fi first 6 #define se second 7 typedef long long ll; 8 typedef pair<int,int> PII; 9 typedef pair<int,PII>piii; 10 int t,a,b; 11 queue<piii>q; 12 void solve1(){ //93ms, 3700KB写法 13 while(!q.empty()) q.pop(); 14 cin>>a>>b; 15 q.push(mp(a,mp(b,0))); 16 int cnt=0; 17 while(!q.empty()){ 18 piii tp=q.front();q.pop(); 19 if(tp.fi==0){ 20 cout<<tp.se.se<<endl; 21 break; 22 } 23 int cnt=tp.se.se; 24 //++cnt; 25 int ta=tp.fi,tb=tp.se.fi; 26 q.push(mp(ta/tb,mp(tb,cnt+1))); 27 q.push(mp(ta,mp(tb+1,cnt+1))); 28 } 29 } 30 31 void solve2(){ //30ms,0KB写法 32 cin>>a>>b; 33 if(a==0) { 34 cout<<0<<endl; 35 return; 36 } 37 int res=a+3; 38 for(int i=0;i<res;++i){ 39 int ans=i,bcs=a,cs=i+b; 40 if(cs==1) continue; 41 while(bcs) bcs/=cs,++ans; 42 res=min(res,ans); 43 } 44 cout<<res<<endl; 45 } 46 int main(){ 47 cin>>t; 48 while(t--) 49 { 50 //solve1(); 51 solve2(); 52 } 53 return 0; 54 }
题意:给出一串数列a,求有多少种不同的数列b,使得a与b只有一个数不同,而且b保持严格单调递增,所有数的取值区间为[1,k]。
题解:
-
- 等价于求对于原数列a,每个元素可以增加或减小的备选可能数。
- 可以用一个新的数组来保存a中每个元素可动范围,b[i]=a[i+1]-a[i-1]-1
- L端点的可动范围应该是1~a[L+1]-1,R端点的可动范围是a[R-1]+1~k。
- 由于题目中每次查询都是区间查询,所以可以使用一个线段树进行维护,有因为查询区间的端点的种类数与非端点的计算方法不同,所以每次查询[L+1,R-1],然后在加上端点的种类数。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define rep(i,a,n) for (int i=a;i<n;i++) 4 #define lson (rt<<1) 5 #define rson (rt<<1 | 1) 6 #define gmid (l+r >> 1) 7 typedef long long ll; 8 const int mod = 1e9+7; 9 int n,q,k,l,r; 10 int a[100500]; 11 int b[100500]; 12 ll sum[400500]; 13 void pushup(int rt) 14 { 15 sum[rt]=(sum[lson]+sum[rson]); 16 } 17 void build(int l,int r,int rt) 18 { 19 if(l==r) 20 { 21 sum[rt]=b[l]; 22 return; 23 } 24 int mid=gmid; 25 build(l,mid,lson); 26 build(mid+1,r,rson); 27 pushup(rt); 28 } 29 int query(int l,int r,int L,int R,int rt) //区间查询 30 { 31 ll ans=0; 32 if(L<=l && r<=R) 33 { 34 return sum[rt]; 35 } 36 int mid=gmid; 37 if(L<=mid) ans=(ans+query(l,mid,L,R,lson)); 38 if(R>mid) ans=(ans+query(mid+1,r,L,R,rson)); 39 return ans; 40 } 41 int main(){ 42 cin>>n>>q>>k; 43 rep(i,1,n+1) cin>>a[i]; 44 rep(i,1,n+1) 45 b[i]=(i==n?k+1:a[i+1])-(i==1?0:a[i-1])-2; 46 build(1,n,1); 47 rep(i,1,q+1){ 48 cin>>l>>r; 49 if(l==r) cout<<k-1<<endl; 50 else cout<<query(1,n,l+1,r-1,1)+a[l+1]-2+k-a[r-1]-1<<endl; 51 } 52 return 0; 53 }
题意: 定义一对有序整数对(a,b)符合:a/b = a mod b 为特殊对,其中 a/b 为计算机整除。要求 a∈[1,x],b∈[1,y]的前提下,有多少对特殊对。
题解:令 a/b = a mod b = k,则 a = b*k + k,其中b > k,缩放后:k*k ≤ b*k+k = a,所以 k ≤ x0.5,对于一个确定的k,求(a,b) 的可行对数。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define rep(i,a,n) for (long long i=a;i<n;i++) 4 typedef long long ll; 5 ll t,a,b,x,y,ans=0; 6 double eu=0.577215664901; 7 int main(){ 8 cin>>t; 9 while(t--) 10 { 11 cin>>x>>y; 12 for(ll i=1;i*i<x;++i) ans+=max(0ll,min(y,x/i-1)-i); 13 cout<<ans<<endl; 14 ans=0; 15 } 16 return 0; 17 }
D-Multiples and Power Differences
题意:给出一个矩阵A,其中A的每个元素都不大于16。要求构造一个新的矩阵B,使得:
-
- 使得B的行数与列数等于A
- B中的每个元素都是A中对应元素的倍数
- B中每个元素与其相邻元素的差,是一个四次方数,即差值等于k4,k∈N。
题解:
-
- 由于A中每个元素都不大于16,那么求一下lcm(1,...,16)=720720,让B矩阵的数全部等于720720,就解决了第二个条件。
- 在从现有的数修改,要使得元素与四周的元素相差是一个k4,而且保持倍数关系,那就可以让四周的数等于720720,然后中间数等于720720+A(i,j)4,有一个倍数加上一个倍数,依然是这个数的倍数,然后不断插空划分之后,就得到一个类似vans棋盘格的矩阵,白点全是720720,黑点全是720720+A(i,j)4
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int n,m; 5 ll ma,mb; 6 ll gcd(ll a,ll b){ 7 return b==0?a:gcd(b,a%b); 8 } 9 ll lcm(ll a,ll b){ 10 return a/gcd(a,b)*b; 11 } 12 ll cal(ll a){ 13 return a*a*a*a; 14 } 15 int main() 16 { 17 cin>>n>>m; 18 ll base=1; 19 for(ll i=1;i<=16;++i) base=lcm(base,i); 20 //cout<<base<<endl; 21 for(int i=1;i<=n;++i) 22 { 23 for(int j=1;j<=m;++j) 24 cin>>ma,mb=(i+j)&1?base+cal(ma):base,cout<<mb<<' '; 25 cout<<endl; 26 } 27 return 0; 28 }
(EF还没做,晚点补。)
(如有错漏,欢迎友好交流指正)