CF #643(div.2)
A. Sequence with Digits
题意: 给定如下递推式
其中 \(minDigit(a_n)\) 和 \(maxDigit(a_n)\) 分别代表 \(a_n\) 十进制表示中 最小 和 最大 的数字,给出 \(a_1\) 和 \(k\) ,让你求 \(a_k\)
\(t~(1 \leq t \leq 1000)\) 组测试数据,每组数据给出 \(a_1\) 和 \(k~(1 \leq a_1 \leq 10^{18},1 \leq k \leq 10^{16})\) ;
分析: 只要第一次 \(minDigit(a_i)=0\) 出现,那么 \(a_i,a_{i+1},...\) 的值都不会变,所以按照公式递推直到算出 \(a_k\) 或者出现 \(minDigit(a_i)=0\) 终止就好了 (关于 \(0\) 在有限且不高次内一定会出现就不证明了,也不咋会证)
代码:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
ll t,n,k;
cin>>t;
while(t--)
{
cin>>n>>k;
if(k==1){
cout<<n<<endl;
continue;
}
k--;
while(k--)
{
ll tmp=n;
ll Min=9,Max=0;
while(tmp)
{
ll res=tmp%10;
tmp/=10;
Min=min(Min,res);
Max=max(Max,res);
}
if(Min==0) break;
else n+=Min*Max;
}
cout<<n<<endl;
}
}
B. Young Explorers
题意: \(T~(1 \leq T \leq 2 \cdot 10^5)\) 组测试数据,每组给出 \(N~(1 \leq N \leq 2 \cdot 10^5)\) 和大小为 \(N\) 的数组 \(e~(1 \leq e_i \leq N)\)
\(\sum N \leq 3 \cdot 10^5\)
对于每组数据,你需要把数组 \(e\) 分成尽可能多的组(不必所有的元素都必须分配),但是每组内的元素需要满足 组的大小大于等于组内任意一个元素,即对于一个大小为 \(m\) 的组 \(b\) ,需要满足 \(b_i \leq m\)
求最多可以分成多少组?
分析: 贪心,把数组 \(e\) 排序 然后从小到大尽量分组划分;
代码:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int N = 3E5+10;
int a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t,n;
cin>>t;
while(t--)
{
cin>>n;
rep(i,1,n) cin>>a[i];
sort(a+1,a+n+1);
int ans=0,xb=1;
while(xb<=n&&xb+a[xb]-1<=n){
if(a[xb]==a[xb+a[xb]-1]) ans++,xb+=a[xb];
else{
int num=a[xb];
xb+=a[xb]-1;
while(xb+1<=n&&num<a[xb]) num++,xb++;
if(num==a[xb]) ans++,xb++;
else break;
}
}
cout<<ans<<endl;
}
}
C. Count Triangles
题意: 给定 \(A,B,C,D~(1 \leq A \leq B \leq C \leq D \leq 5 \cdot 10^5)\) ,求有多少组 \((x,y,z)\) 满足 \(A \leq x \leq B \leq y \leq C \leq z \leq D\) 且构成非退化三角形;
分析: 因为 \(x \leq y \leq z\) ,差分一下 \(x+y\) 的出现次数 然后求一遍前缀和 再枚举 \(z\) ;
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int N = 1E6+10;
int A,B,C,D;
ll num[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>A>>B>>C>>D;
rep(i,A,B)
{
num[i+B]++;
num[i+C+1]--;
}
rep(i,1,N-1) num[i]+=num[i-1]; //第一遍求出num[i]表示x+y==i有几种
rep(i,1,N-1) num[i]+=num[i-1]; //第二遍求前缀和
ll ans=0;
rep(i,C,D) ans+=num[N-1]-num[i];
cout<<ans;
}
D. Game With Array
题意: 给定 \(N\) 和 \(S~(1 \leq N \leq S \leq 10^6)\) ,现在要你构造出一个大小为 \(N\) 的数组 \(s~(0<s_i \leq S)\) 然后选择一个数 \(K~(0 \leq K \leq S)\),在数组满足 \(\sum s_i=S\) 的情况下,无法在数组中选取若干元素的和 \(sum\) 使得 \(sum=K~~or~~sum=S-K\);
分析: 构造方法不只一种,但是 \(S<2*N\) 肯定无解,然后考虑 \(K=1\) 的话,构造出 \(2,2...,S-2*(N-1)\) 这类形式的序列,就可以满足题意
代码:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,s;
cin>>n>>s;
if(2*n>s)
{
cout<<"NO";
return 0;
}
cout<<"YES\n";
for(int i=1;i<n;i++) cout<<2<<' ';
cout<<s-2*(n-1)<<endl;
cout<<1;
}
E. Restorer Distance
题意: 先给出 \(N,A,R,M~(1 \leq N \leq 10^5,0 \leq A,R,M \leq 10^4)\) ,然后给出大小为 \(N\) 的数组 \(h~(0 \leq h_i \leq 10^9)\) 分别代表 \(N\) 根砖柱的高度(1单位高度代表一块砖),现在有三种操作
- 花费代价 A ,在某一根砖柱上加一块砖
- 花费代价 R ,从某一根砖柱上拿走一块砖
- 花费代价 M ,从某一根砖柱上拿一块砖放到另一根砖柱上
现在要求用最小的代价使得所有砖柱高度一致
分析: 三分
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int MAXN = 1E5+10;
int N,A,R,M;
ll a[MAXN],sum[MAXN];
ll cal(ll H)
{
int x=1;
while(x<=N&&a[x]<H) x++;
ll left=0;
if(x<=N) left=sum[N]-sum[x-1]-H*(N-x+1);
ll need=0;
if(x>1) need=H*(x-1)-sum[x-1];
ll cost=0;
if(A+R>=M){
if(left>=need) cost+=need*M,left-=need,need=0;
else cost+=left*M,need-=left,left=0;
}
cost+=left*R;
cost+=need*A;
return cost;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>N>>A>>R>>M;
rep(i,1,N) cin>>a[i];
sort(a+1,a+N+1);
rep(i,1,N) sum[i]=sum[i-1]+a[i];
ll L=0,R=1E9+1;
while(L+1<R)
{
ll m1=(L+R)>>1;
ll m2=(m1+R)>>1;
if(cal(m1)<cal(m2)) R=m2;
else L=m1;
}
ll ANS=cal(L);
cout<<ANS;
}
F. Guess Divisors Count
题意: 交互题,预先设定一个数 \(X~(1 \leq X \leq 10^9)\) ,让你通过交互得出 \(X\) 有多少个因数,你有至多 22 次询问,每次询问形式 ? Q
\((1 \leq Q \leq 10^{18})\) ,然后会反馈 GCD(X,Q)
,即最大公约数;设 \(X\) 实际有 \(d\) 个因数,你给出的答案为 \(ans\) ,那么只要
- \(|ans-d| \leq 7\)
- \(\frac{1}{2} \leq \frac{ans}{d} \leq 2\)
至少满足上述两个条件之一,就判正确
分析: 肯定会先想到素数分解的形式:\(X=p_1^{a_1} \cdot p_2^{a_2} \cdots p_m^{a_m}\) ,那么 \(d=(a_1+1)*(a_2+1) \cdots (a_m+1)\) ;然后明确一点,题目给定了误差限制,所以可以推测不可能在 22 次询问里求得准确答案,即不是 X 的每个素因子都能询问到,可以从这一点考虑:
- 只有 22 次询问机会,\((1 \leq X \leq 10^9)\) ,\((1 \leq Q \leq 10^{18})\),所以,1 次询问考虑询问多个素数的乘积;
- 考虑多个素数的乘积 \((1 \leq Q \leq 10^{18})\) ,其中若有较小的素数,那么它的次数肯定不能是 1 ,否则若 \(X\) 中关于这个素数的次数很高那么这个素数的询问完全是没有用的,所以得提高次数;然后,最小的素数是 2 且 \(2^{30}>10^9 \geq X\) ,所以可以 以 \(2^{10}=1024\) 为上界,提高乘积内每个素数的次数,这样一个 Q 内大概会有 5,6 个素数,22 次询问从小到大 大概可以询问到 八百多的素数;极端情况下,我们计算的某个素数的次数可能只统计了刚好超过 \(\frac{1}{3}\) ,例如 \(X=2^{29}\);所以得出最后的结果再乘以 2 ,即
ans*2
,那么对于已经计算过的素数误差完全是在条件2范围内的,而对于之后的素数出现的情况,分情况考虑: - 若之后的素数出现了 3 次,那么前面的素数一个都不会出现,因为 \((1 \leq X \leq 10^9)\),标准因数个数最大为 \(d=2 \times 2 \times 2=8\),而我们 ans 初始是1,最后乘以2,\(|ans-d| \leq 7\) 成立,满足条件 1;
- 若之后的素数出现了 2 次,那么前面的素数的所有出现次数完全被计算了(因为 \(1 \leq X \leq 10^9\)),除开后面的两个素数之后,X 最多只剩下 1000 左右;此时后面的素数 d 的影响最多是 \(2 \times 2=4\) 倍级别,所以 ans*2 之后是满足条件 2 的;
- 若之后的素数出现了 1 次,极端情况下,前面的素数最多被少算了 1 倍 ,例如 \(X=2^{20} \times 863\),此时 ans*2 之后依旧满足条件 2;
代码:
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define ll unsigned long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int N = 1000;
vector<ll>pm; //素数
vector<ll>pp; //提高次数的素数
vector<ll>test; //多个提高次数的素数的乘积
void ready()
{
bool vis[N]={0};
rep(i,2,N-1)if(!vis[i]){
pm.pb(i);
for(int j=i;j<N;j+=i) vis[j]=1;
}
for(auto v:pm)
{
ll x=v;
while(x*v<=1024)x*=v;
pp.pb(x);
}
ll res=1;
int cnt=0;
for(auto v:pp)
{
if(res*v>1e18) test.pb(res),res=v,++cnt;
else res*=v;
if(cnt==22) {cout<<"---"<<v<<endl;break;}
}
if(res>1) test.pb(res);
}
ll ask(ll m)
{
cout<<"? "<<m<<endl;
ll res;cin>>res;
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
ready();
for(auto v:pm) cout<<v<<endl;
int t;
cin>>t;
while(t--)
{
ll ANS=1;
rep(k,0,21)
{
ll ans=ask(test[k]),cnt;
for(auto v:pm){
cnt=0;
while(ans%v==0) cnt++,ans/=v;
ANS*=(cnt+1);
}
}
cout<<"! "<<ANS*2<<endl;
}
}