牛客2025多校 R7
牛客2025多校 R7
C:
题目大意:
void solve(){
int n;
cin>>n;
vector<int> a(n+1);
for (int i=1;i<=n;i++) cin>>a[i];
vector<int> pre(n+1);
vector<int> suf(n+2);
for (int i=1;i<=n;i++)
pre[i]=max(pre[i-1],a[i]);
suf[n+1]=2e9;
for (int i=n;i>=1;i--)
suf[i]=min(suf[i+1],a[i]);
int ans=0;
for (int i=1;i<=n;i++)
ans=max(ans,pre[i]-suf[i+1]);
cout<<ans<<endl;
}
维护每个位置的前缀最大值和后缀最小值,如果要修改为非递减序列,那么至少要将前缀最大值减到和后缀最小值相同
F:
题目大意:
const int mod=998244353;
void solve(){
int n;
cin>>n;
if (n==1){
cout<<0<<endl;
return;
}
vector<int> a(n+1);
for (int i=1;i<=n;i++) cin>>a[i];
sort(a.begin()+1,a.end());
int m=a[1]+a[n]>>1;
while (m){
int mx=0,mn=1e9;
for (int i=1;i<=n;i++){
a[i]=abs(a[i]-m);
mx=max(mx,a[i]);
mn=min(mn,a[i]);
}
m=mx+mn>>1;
}
map<int,int> mp;
for (int i=1;i<=n;i++) mp[a[i]]++;
vector<pair<int,int>> x;
for (auto [k,v]:mp) x.push_back({k,v});
LL ans=0;
for (int i=0;i<x.size();i++)
for (int j=i+1;j<x.size();j++)
ans=1ll*(ans+abs(x[j].first-x[i].first)*x[j].second*x[i].second)%mod;
cout<<ans;
}
要使得所有元素的差的绝对值最小,那么就要让所有元素越接近
我们每次操作可以使得所有元素都变为 \(\lvert a_i-v\rvert\) ,这样的问题有一种经典的处理方式,那就是使得每次选定的 \(v\) 是这个序列极大极小值差的一半
减去这样的一个值后,一定不会使所有元素的差的绝对值之和变大,也就是这是一种不劣的操作
可以证明,这样的操作一定是最优的,并且最多执行 \(O(\log n)\) 次
所以记录下每轮过后的极大极小值,然后逐渐迭代,最后利用乘法原理计算答案
G:
题目大意:
const int N=1e6;
vector<int> p;
int spf[N+1];
int dp[N+1];
void init(){
for (int i=2;i<=N;i++){
if (spf[i]==0){
spf[i]=i;
p.push_back(i);
}
dp[i]=dp[i/spf[i]]^1;
for (auto it:p){
if (it*i>N||it>i) break;
spf[it*i]=it;
}
}
}
void solve(){
int n;
cin>>n;
vector<int> ans;
for (int i=1;i<=n;i++){
if (ans.size()==n/2) break;
if (dp[i]) ans.push_back(i);
}
for (auto i:ans) cout<<i<<' ';
cout<<endl;
}
如果 \(u\) 是一个完全平方数,那么 \(u\) 在进行质因子分解后,每个质因子的次数都是偶数(和也为偶数)
在一个集合中任取 \(3\) 个数 \(x,y,z\)(可以相同) ,他们的乘积 \(xyz\) 不为完全平方数的充分必要条件是:
这三个数在经过质因子分解后所有质因子的次数和都为奇数
可以证明这样的数在 \(N\) 的范围内至少有 \(N/2\) 个(\(N\) 极大时存在特例)
J:
题目大意:
const int mod=998244353;
LL ksm(LL a,LL b,LL p){
LL res=1;
a%=p;
while (b){
if (b&1) res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
LL func(LL a,LL b,LL c,LL d){
LL g=__gcd(a,c);
if (b==0||g==1) return 1;
if (b>d){
swap(a,c);
swap(b,d);
}
return ksm(g,b,mod)*func(a/g,b,c,d-b)%mod;
}
void solve(){
LL a,b,c,d;
cin>>a>>b>>c>>d;
if (__gcd(a,c)==1){cout<<1<<'\n';return;}
cout<<func(a,b,c,d)<<'\n';
}
考察GCD 有这样的性质:
- \(\mathrm{gcd}(a,bc)=\mathrm{gcd}(a,b)\times \mathrm{gcd}(a/\mathrm{gcd}(a,b),c)\)
- \(\mathrm{gcd}(a^n,b^n)=\mathrm{gcd}(a,b)^n\)
题目的 \(\mathrm{gcd}(a^b,c^d)\) 可以递归的拆分成 \(\gcd (a,c)^b \times \gcd (a^b/\gcd (a,c)^b,c^{d-b})\) ,如果 \(b>d\) 那么就交换 \(a,c\) 的位置方便递归处理
可以证明递归的操作最多执行 \(\log a\) 次,总的时间复杂度为 \(O(T\log^2 a)\)
A:
题目大意:
int ans,res;
int tmp[100010];
int a[100010];
void mergesort(int a[],int l,int r){
if (r<=l) return ;
int mid=l+r>>1;
mergesort(a,l,mid);
mergesort(a,mid+1,r);
int k=0,i=l,j=mid+1;
while (i<=mid&&j<=r){
if (a[i]<=a[j]) tmp[k++]=a[i++];
else{
tmp[k++]=a[j++];
res+=mid-i+1;
}
}
while(i<=mid) tmp[k++]=a[i++];
while(j<=r) tmp[k++]=a[j++];
for (int i=l;i<=r;i++) a[i]=tmp[i-l];
}
void solve(){
int id,m,k,n;
cin>>id>>m>>k>>n;
for (int i=1;i<=m;i++){
ans=0;
for (int j=1;j<=k;j++){
res=0;
for (int u=0;u<n*n;u++) cin>>a[u];
mergesort(a,0,n*n-1);
ans+=(res&1);
}
if (ans==0) cout<<0;
else cout<<1;
}
}
逆时针旋转一个 \(4\times 4\) 的子块不会改变矩阵按行拆分后产生的排列的逆序对的奇偶性
证明:
假设有序列为 \(a_1,a_2,\cdots ,a_n\) ,交换任意两个数的位置 \(a_i,a_j\) 会改变一次逆序对的奇偶性
先考虑交换相邻两个数产生的影响,\(a_i,a_{i+1}\to a_{i+1},a_i\),显然只会产生 \(1\) 的贡献,\([1:i-1],[i+2:n]\) 这两段上的元素不会对交换后的序列的逆序对数量造成贡献
然后是交换 \(a_i,a_{j}\) 产生的影响,可以看作先将序列循环右移交换操作一次 \(a_{i+1},a_{i+2},\cdots,a_j,a_i\) ,然后将 \(a_j\) 与前面相邻的数交换直到变为 \(a_j,a_{i+1},\cdots ,a_{j-1},a_i\) 总共 \((j-1)+(j-1-1)\) 次交换相邻两数的操作,所以也会导致序列的逆序对数量的奇偶性改变一次
对原矩阵的 \(4\times 4\) 的子块进行顺时针旋转 \(90^{\circ}\) 的操作后,每个旋转位置上的数都要改变 \(3\) 次逆序对的奇偶性
共计 \(4\) 组元素,所以改变奇偶性 \(3\times 4\) 次,相当于不改变奇偶性
所以只需要判断每套玩具中是否所有的玩具都没有被改变奇偶性,如果是,那么就可以断言在 \(1/2^{10}\) 的概率下这套玩具没有被弄坏