题意:
给出两个数,a和b,有两种操作,一种是a/b(计算机整除,只保留整数位),另一种是b+1,求最少通过多少次操作可以使得a==0。
题解:
- BFS。
- (UPD:2021-02-13-17:14)可以得出对于每一步的操作,先增加b,再去除,整体会比先除在增加更优,因为 a/b > a/(b+1)。solve2()即为30ms写法。
代码:
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define mp make_pair
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<int,PII>piii;
int t,a,b;
queue<piii>q;
void solve1(){ //93ms, 3700KB写法
while(!q.empty()) q.pop();
cin>>a>>b;
q.push(mp(a,mp(b,0)));
int cnt=0;
while(!q.empty()){
piii tp=q.front();q.pop();
if(tp.fi==0){
cout<<tp.se.se<<endl;
break;
}
int cnt=tp.se.se;
//++cnt;
int ta=tp.fi,tb=tp.se.fi;
q.push(mp(ta/tb,mp(tb,cnt+1)));
q.push(mp(ta,mp(tb+1,cnt+1)));
}
}
void solve2(){ //30ms,0KB写法
cin>>a>>b;
if(a==0) {
cout<<0<<endl;
return;
}
int res=a+3;
for(int i=0;i<res;++i){
int ans=i,bcs=a,cs=i+b;
if(cs==1) continue;
while(bcs) bcs/=cs,++ans;
res=min(res,ans);
}
cout<<res<<endl;
}
int main(){
cin>>t;
while(t--)
{
//solve1();
solve2();
}
return 0;
}
题意:
给出一串数列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],然后在加上端点的种类数。
代码:
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define lson (rt<<1)
#define rson (rt<<1 | 1)
#define gmid (l+r >> 1)
typedef long long ll;
const int mod = 1e9+7;
int n,q,k,l,r;
int a[100500];
int b[100500];
ll sum[400500];
void pushup(int rt)
{
sum[rt]=(sum[lson]+sum[rson]);
}
void build(int l,int r,int rt)
{
if(l==r)
{
sum[rt]=b[l];
return;
}
int mid=gmid;
build(l,mid,lson);
build(mid+1,r,rson);
pushup(rt);
}
int query(int l,int r,int L,int R,int rt) //区间查询
{
ll ans=0;
if(L<=l && r<=R)
{
return sum[rt];
}
int mid=gmid;
if(L<=mid) ans=(ans+query(l,mid,L,R,lson));
if(R>mid) ans=(ans+query(mid+1,r,L,R,rson));
return ans;
}
int main(){
cin>>n>>q>>k;
rep(i,1,n+1) cin>>a[i];
rep(i,1,n+1)
b[i]=(i==n?k+1:a[i+1])-(i==1?0:a[i-1])-2;
build(1,n,1);
rep(i,1,q+1){
cin>>l>>r;
if(l==r) cout<<k-1<<endl;
else cout<<query(1,n,l+1,r-1,1)+a[l+1]-2+k-a[r-1]-1<<endl;
}
return 0;
}
题意:
定义一对有序整数对(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) 的可行对数。
代码:
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (long long i=a;i<n;i++)
typedef long long ll;
ll t,a,b,x,y,ans=0;
double eu=0.577215664901;
int main(){
cin>>t;
while(t--)
{
cin>>x>>y;
for(ll i=1;i*i<x;++i) ans+=max(0ll,min(y,x/i-1)-i);
cout<<ans<<endl;
ans=0;
}
return 0;
}
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
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
ll ma,mb;
ll gcd(ll a,ll b){
return b==0?a:gcd(b,a%b);
}
ll lcm(ll a,ll b){
return a/gcd(a,b)*b;
}
ll cal(ll a){
return a*a*a*a;
}
int main()
{
cin>>n>>m;
ll base=1;
for(ll i=1;i<=16;++i) base=lcm(base,i);
//cout<<base<<endl;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
cin>>ma,mb=(i+j)&1?base+cal(ma):base,cout<<mb<<' ';
cout<<endl;
}
return 0;
}