CF2020
A. Find Minimum Operations
难度:红
转换进制,每一位上数字相加。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll t,n,k,ans;
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--){
cin>>n>>k;
if(k==1)cout<<n<<'\n';
else{
ans=0;
while(n>=k){
ans+=n%k;
n/=k;
}
ans+=n;
cout<<ans<<'\n';
}
}
return 0;
}
B. Brightness Begins
难度:橙
场上临时打了个表找规律。发现 \(n-\lfloor\sqrt{n}\rfloor=k\)。于是过了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll t,k;
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--){
cin>>k;
if(k==0){
cout<<1<<'\n';
continue;
}
ll a=sqrtl(k);
if((a+k)-(ll)sqrtl(a+k)==k)cout<<a+k<<'\n';
else cout<<a+k+1<<'\n';
}
return 0;
}
C. Bitwise Balancing
对于每一位分类讨论。
场上分讨调了好久没出来,悲剧了qwq
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll t,ans,b,c,d;
ll fj(ll b,ll c,ll d){
ll ret=0;
for(ll i=0;i<=62;i++){
ll nowd=((d>>i)&(1ll)),nowc=((c>>i)&(1ll)),nowb=((b>>i)&(1ll));
if((nowd==0)&&(nowc==0)&&(nowb==0))ret+=0;
else if((nowd==0)&&(nowc==0)&&(nowb==1))return -1;
else if((nowd==0)&&(nowc==1)&&(nowb==0))ret+=(1ll<<i);
else if((nowd==0)&&(nowc==1)&&(nowb==1))ret+=(1ll<<i);
else if((nowd==1)&&(nowc==0)&&(nowb==0))ret+=(1ll<<i);
else if((nowd==1)&&(nowc==0)&&(nowb==1))ret+=0;
else if((nowd==1)&&(nowc==1)&&(nowb==0))return -1;
else ret+=0;//if((nowd==1)&&(nowc==1)&&(nowb==1))
}
if(ret>(1ll<<61))return -1;
return ret;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--){
cin>>b>>c>>d;
cout<<fj(b,c,d)<<'\n';
}
return 0;
}
D. Connect the Dots
难度:黄-绿
首先,直接用并查集维护会T飞。
先把操作记录下来,再遍历 \(1\sim n\) 传递操作,并查集维护一下就行了。
#include<bits/stdc++.h>
#define ll long long
#define mxn 200010
using namespace std;
ll T,n,m,a,d,k,f[mxn],num[mxn][15];
int fnd(int x){
if(x==f[x])return x;
return f[x]=fnd(f[x]);
}
void solve(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=10;j++)
num[i][j]=0;
f[i]=i;
}
for(int i=1;i<=m;i++){
cin>>a>>d>>k;
num[a][d]=max(num[a][d],k);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=10;j++){
if(i<=j)break;
if(num[i-j][j])f[fnd(i)]=fnd(i-j);
}
for(int j=1;j<=10;j++)
if(num[i][j]>1&&i+j<=n)
num[i+j][j]=max(num[i+j][j],num[i][j]-1);
}
set<int> s;
for(int i=1;i<=n;i++)
s.emplace(fnd(i));
cout<<s.size()<<'\n';
return;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--)solve();
}
E. Expected Power
难度:绿
看见期望我就跑
考虑概率dp。
容易发现不管怎么异或,最终异或和的范围总会在 \([0,1023]\) 内。
定义 \(dp_{i,j}\) 为前 \(i\) 位中异或和为 \(j\) 的概率。
当不选 \(a_i\) 时,有
\(dp_{i,j}=dp_{i,j}+(1-p_i)*dp_{i-1,j}\)
选了 \(a_i\) 时,有
$ dp_{i,j}=dp_{i,j}+p_i*dp_{i-1,j\oplus a_i} $
注意到 \(dp_{i}\) 只由 \(dp{i-1}\) 转移,所以可以省一维。
#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
#define mxn 200010
using namespace std;
ll t,n,p[mxn],a[mxn],frac,ans;
ll quickpow(ll a,ll x){
ll ret=1,base=a;
while(x){
if(x&1)ret=ret*base%mod;
base=base*base%mod;
x>>=1;
}
return ret;
}
void solve(){
cin>>n;
ans=0;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>p[i];
ll dp[1030][2]={0};
dp[0][0]=1;
for(int i=1;i<=n;i++){
ll now=i%2,lst=(i%2)^1;
for(int j=0;j<1024;j++){
dp[j][now]=0;
dp[j][now]=(dp[j][now]+dp[j][lst]*(10000-p[i]))%mod;
dp[j][now]=(dp[j][now]+dp[j^a[i]][lst]*p[i])%mod;
dp[j][now]=dp[j][now]*frac%mod;
}
}
for(ll i=0;i<1024;i++)
ans=(ans+i*i*dp[i][n%2]%mod)%mod;
cout<<ans<<'\n';
return;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
frac=quickpow(10000,mod-2);
cin>>t;
while(t--)solve();
return 0;
}
注:该代码不保证可过,我交的时候TLE了,后面加了快读快写才过的。
F. Count Leaves
难度:紫
这题实在想不到正解,被迫看solution了qaq
容易发现,叶子数量等于选择 \(d+1\) 个数 \(((a_0,a_1,...,a_d),\) 其中 \(a_d=n,a_i|a_{i+1}(i=0...d-1))\) 的方法数。
定义 \(g(n)=f(n,d),(d\) 已给定)。手推一下发现这是个积性函数,即当 \(p,q\) 互质时,有 \(g(p)*g(q)=g(p*q)\)。
当 \(n\) 为某个素数 \(p\) 的非负整数幂次时(即 \(n=p^b\)),明显 \(a_0,a_1,...,a_d\) 可以写成 \(p_{b_0},p_{b_1},...,p_{b_d}=x(b_0\leq b_1\leq...\leq b_d=b)\)。
于是有 \(g(n)=\tbinom{x+d}{d}\)。
然后官方solution上说是受到 Meissel–Lehmer 算法(一种快速计算质数个数的算法)的启发搞了个dp。
当然关于这个算法的介绍也不用去看,OI-wiki上写的像一坨。
总之是搞了一个dp。令 \(dp(n,x)=\sum^n_{i=1,spf(i)\geq x}g(i)\),其中 \(spf(i)\) 表示 \(i\) 的最小质因子。
我猜看到这么大一串式子你会懵逼。讲的就是从 \(1..n\) 中选出满足其最小质因子大于等于 \(x\) 的数 \(i\),求 \(g(i)\) 的和。
于是这里有一大堆式子:
手推过程略。
明显,\(g(n)=dp(n,2)\),于是可以求出答案。
时间复杂度 \(O(n^{\frac{2}{3}})\)。
这里就先把官方代码贴上面吧(可读性极高),到时候再补自己的。
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define big_lim 1001
#define small_lim 1000001
#define mod 1000000007
#define ncrlim 3500000
using namespace std;
ll powmod(ll base,ll exponent){
ll ans=1;
if(base<0)base+=mod;
while(exponent){
if(exponent&1)ans=(ans*base)%mod;
base=(base*base)%mod;
exponent/=2;
}
return ans;
}
ll gcd(ll a,ll b){
if(b==0) return a;
else return gcd(b,a%b);
}
ll primes_till_i[small_lim];
ll primes_till_bigger_i[big_lim];
vector<ll> sieved_primes[small_lim];
vector<ll> sieved_primes_big[big_lim];
vector<int> prime;
int N,k,d;
void sieve(){//普通的埃氏筛
vector<int> lpf(small_lim);
ll pw;
for(int i=2;i<small_lim;i++){
if(!lpf[i]){
prime.push_back(i);
lpf[i]=i;
}
for(int j:prime){
if((j>lpf[i])||(j*i>=small_lim))break;
lpf[j*i]=j;
}
}
for(int i=2;i<small_lim;i++)
primes_till_i[i]=primes_till_i[i-1]+(lpf[i]==i);
}
ll count_primes(ll n,int ind){
if(ind<0)return n-1;
if(1ll*prime[ind]*prime[ind]>n){
if(n<small_lim)return primes_till_i[n];
if(primes_till_bigger_i[N/n])return primes_till_bigger_i[N/n];
int l=-1,r=ind;
while(r-l>1){
int mid=(l+r)>>1;
if(1ll*prime[mid]*prime[mid]>n)r=mid;
else l=mid;
}
return primes_till_bigger_i[N/n]=count_primes(n,l);
}
int sz;
if(n<small_lim)sz=sieved_primes[n].size();
else sz=sieved_primes_big[N/n].size();
ll ans;
if(sz<=ind){
ans=count_primes(n,ind-1);
ans-=count_primes(n/prime[ind],ind-1);
ans+=ind;
if(n<small_lim) sieved_primes[n].push_back(ans);
else sieved_primes_big[N/n].push_back(ans);
}
if(n<small_lim) return sieved_primes[n][ind];
else return sieved_primes_big[N/n][ind];
}
ll count_primes(ll n){
if(n<small_lim) return primes_till_i[n];
if(primes_till_bigger_i[N/n]) return primes_till_bigger_i[N/n];
return count_primes(n,prime.size()-1);
}
int fact[ncrlim];
int invfact[ncrlim];
void init_fact(){
fact[0]=1;
for(int i=1;i<ncrlim;i++) fact[i]=(1ll*fact[i-1]*i)%mod;
invfact[ncrlim-1]=powmod(fact[ncrlim-1], mod-2);
for(int i=ncrlim-1;i>0;i--) invfact[i-1]=(1ll*invfact[i]*i)%mod;
}
int ncr(int n,int r){
if(r>n||r<0)return 0;
int ans=fact[n];
ans=(1ll*ans*invfact[n-r])%mod;
ans=(1ll*ans*invfact[r])%mod;
return ans;
}
ll calculate_dp(ll n,int ind){
if(n==0)return 0;
if(prime[ind]>n) return 1;
ll ans=1,temp;
if(1ll*prime[ind]*prime[ind]>n){
temp=ncr(k+d,d);
temp*=count_primes(n)-ind;
ans=(ans+temp)%mod;
return ans;
}
ans=0;
ll gg=1;
ll mult=d;
while(gg<=n){
temp=calculate_dp(n/gg,ind+1);
temp*=ncr(mult,d);
ans=(ans+temp)%mod;
mult+=k;
gg*=prime[ind];
}
return ans;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
sieve();//质数预处理
init_fact();//组合数预处理
int t;
cin>>t;
while(t--){
cin>>N>>k>>d;
cout<<calculate_dp(N,0)<<'\n';
for(int i=1;i<big_lim;i++){
primes_till_bigger_i[i]=0;
sieved_primes_big[i].clear();
}
}
return 0;
}
标签:int,CF2020,ll,Codeforces,long,ans,Div,dp,define
From: https://www.cnblogs.com/nagato--yuki/p/18442684