A-签到题
注意到,,故
。
对任意的,令
,则
,此时
。
#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)printf("%d ",i);
return 0;
}
B-Bob的蛋糕店
设Alice拿走的蛋糕分别是第个,根据质心公式有
,直接模拟即可。
复杂度为。
注意:为了避免精度问题,判断时,交叉相乘再相减等于零即可。
#include<bits/stdc++.h>
using namespace std;
int n,k,a[25],A,B,fl,q[25];
void dfs(int deep,int x){
if(deep==k+1){
int sum=0;
for(int i=1;i<=k;i++)
sum+=B*a[q[i]]*q[i]-A*a[q[i]];
if(sum==0)fl=1;
return ;
}
for(int i=x;i<=n+deep-k;i++){
q[deep]=i;
dfs(deep+1,i+1);
}
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i],A+=a[i]*i,B+=a[i];
dfs(1,1);
if(fl)cout<<"Yes";
else cout<<"No";
return 0;
}
C-修复排列
题目核心需求
给定两个排列 (初始排列)和
(修复用排列),每次破坏会将
位置的
变为
。需通过 “用
替换
” 的操作,将
恢复为
的排列,求第
次破坏后最少的操作次数(每次答案独立计算)。
核心思路
要恢复排列,关键是解决 “修复值重复” 问题:
破坏位置 必须修复(
不能在排列中),修复值为
;
但 可能在原
的未破坏位置存在(比如
,原
未破坏,会重复);
需追踪这种 “重复冲突链”:修复一个位置后,若其修复值在原 中对应位置未处理,需继续修复该位置,直到无新冲突。
代码通过以下工具实现该逻辑:
:记录值
在原排列
中的下标(因
是排列,每个
唯一对应一个下标);
:记录 “必须修复的值”(每个值对应唯一位置,
的大小即为最少操作次数,避免重复处理冲突链)。
代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define fixed(x) fixed<<setprecision(x)
const int N=2e5+5;
int main(){
int n;cin>>n;
vector<int>p(n+1),id(n+1),d(n+1);
for(int i=1;i<=n;i++)cin>>p[i];
for(int i=1;i<=n;i++)cin>>id[i];
for(int i=1;i<=n;i++)cin>>d[i];
map<int,int>mp;
for(int i=1;i<=n;i++)mp[p[i]]=i;
set<int>st;
for(int i=1;i<=n;i++){
int x=d[id[i]];
while(st.find(x)==st.end()){
st.insert(x);
x=d[mp[x]];
}
cout<<st.size()<<' ';
}
return 0;
}
D-图G
根据的性质,当且仅当
时,点
和点
连有一条边。
即:。
设表示任意的
,满足
的个数,当
时,跟点
连有边的点
有
个。
复杂度为。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,M=1005;
int n,a[N],b[N];
ll ans,f[M][M];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)scanf("%d",&b[i]);
for(int i=1;i<=n;i++){
if(a[i]%b[i]==0){
a[i]/=b[i];
for(int j=1;j<=1000;j++){
if(a[i]%j==0){
ans+=f[j][b[i]];
f[b[i]][j]++;
}
}
}
}
printf("%lld",ans);
return 0;
}
E-小R的min
根据的定义,易得:对于任意的
,将
按升序排序后,当
为中位数时,
最小。记
,故求第
小的数
。
对于每次询问,我们可以考虑二分中位数,找到最小的
满足
。
虽然不好计算,但是注意到
的单调性,我们可以考虑容斥,即:
.
对于任意的,我们可以先
预处理出
.
设,根据
的单调性,
还表示最大的
满足
,故可以二分
,在
内计算出
,而
即
的前缀和。因为
是中位数,而且
必定是数组
中的数,所以只需要预处理数组
中的数即可,离散化后总复杂度为
。
同理,我们也可以预处理。
最后,当时,对于任意的
,有
,故
;当
时,对于任意的
,有
,故
。
复杂度为。
不过,内测的时候发现常数较小的做法刚好可以通过,赛时发现许多选手
也通过了...
#include <bits/stdc++.h>
using namespace std;
const int N=1005;
int n,m,a[N],f[N][N],sl[N][N],sr[N][N],b[N][N];
bool check(int l,int r,int x,int k){
int sum=0;
if(b[r][x]>=l)sum=sl[r][x]+sr[l][x]+(l-1)*(n-r)-sl[n][x];
return sum>=k;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
int mi=a[i];
for(int j=i;j<=n;j++){
mi=min(mi,a[j]);
f[i][j]=mi;
}
}
sort(a+1,a+n+1);
int len=unique(a+1,a+n+1)-a-1;
for(int i=1;i<=len;i++) {
for(int j=1;j<=n;j++){
int l=0,r=j,mid;
while(l<r){
mid=(l+r+1)>>1;
if(f[mid][j]<=a[i])l=mid;
else r=mid-1;
}
sl[j][i]=sl[j-1][i]+l;
b[j][i]=l;
}
for(int j=n;j;j--){
int l=j,r=n+1,mid;
while(l<r){
mid=(l+r)>>1;
if(f[j][mid]<=a[i])r=mid;
else l=mid+1;
}
sr[j][i]=sr[j+1][i]+n+1-l;
}
}
int L,R,k;
while(m--){
scanf("%d%d",&L,&R);
k=((R-L+1)*(R-L+2)/2+1)/2;
int l=1,r=len,mid;
while(l<r){
mid=(l+r)>>1;
if(check(L,R,mid,k))r=mid;
else l=mid+1;
}
printf("%d\n",a[l]);
}
return 0;
}
F-种树
首先,我们先证明一个结论: 。
设 ,其中
。
。
即求: 。
接着, 对该式子进行莫比乌斯反演:
。
最后,我们可以用杜教筛计算出结果:
设 。
因为 ,
所以 。
复杂度为 。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+80,mod=1e9+7;
const ll inv3=333333336,inv2=500000004;
ll n,mu[N],p[N],M=1e6;
bool flg[N];
ll sum(ll x){
return x%mod*(x%mod+1)%mod*inv2%mod;
}
ll sum2(ll x){
x%=mod;
return x*(x+1)%mod*(x*2%mod+1)%mod*inv2%mod*inv3%mod;
}
void init(){
int top=0;
mu[1]=1;
for(int i=2;i<=M;i++){
if(!flg[i]){
p[++top]=i;
mu[i]=-1;
}
for(int j=1;j<=top&&p[j]*i<=M;j++){
flg[p[j]*i]=true;
if(i%p[j]==0){
mu[i*p[j]]=0;
break;
}
mu[i*p[j]]=-mu[i];
}
}
for(ll i=1;i<=M;i++)mu[i]=(mu[i]*i%mod*i%mod+mu[i-1])%mod;
}
map<ll,ll> mp;
ll SF(ll x){
if(x<=M)return mu[x];
if(mp[x])return mp[x];
ll ans=1;
for(ll l=2,r;l<=x;l=r+1){
r=x/(x/l);
ans=(ans-(sum2(r)-sum2(l-1))%mod*SF(x/l)%mod)%mod;
}
return mp[x]=(ans+mod)%mod;
}
int main() {
scanf("%lld",&n);
M=min(M,n),init();
ll ans=0;
for(ll l=1,r;l<=n;l=r+1){
ll x=n/l,y=sum(x);
r=n/x;
ans=(ans+y*y%mod*(SF(r)-SF(l-1))%mod)%mod;
}
printf("%lld",(ans+mod)%mod);
return 0;
}



京公网安备 11010502036488号