E. Permutation Shift
思路:
原问题等价于把往左挪
位,然后最多交换
次得到原排列,求有多少种
。
假设排列表示原排列,
表示原排列往右挪
位得到的排列,那么当
时,
对应位置上数字相同的个数为
。
一个通常能想到的套路就是枚举,然后把排列
往左挪
位得到排列
,然后判断排列
能不能通过最多
次交换得到原排列。一个很简单的结论就是,排列
和排列
如果有
个位置不同,那么最少需要交换
次,最多需要交换
次。转化一下就是,排列
最小需要有
个对应位置的数字相同。
假设有个
满足这一题的条件,满足条件的
的集合
,那么排列
对应位置上数字相同的个数不小于
,又因为当
时,
对应位置上数字相同的个数为
。所以有不等式
,而
,解得
。也就是说
最多只有三种情况,当排列
对应位置上数字相同的个数不小于
时可以直接暴力判断是否满足题目条件。
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5+7,mod=998244353;
vector<int>v;
int cnt[maxn],a[maxn],p[maxn],n,m;
bool vis[maxn];
bool check(int k) {
int tot(0);
for(int i=k+1;i<=n;++i) p[++tot]=a[i],vis[i]=false;
for(int i=1;i<=k;++i) p[++tot]=a[i],vis[i]=false;
int ans=n,pos;
for(int i=1;i<=n;++i) {
if(vis[i]) continue;//i已经交换过了
--ans;
pos=i;
while(!vis[pos]) {
vis[pos]=true;
pos=p[pos];
}
}
return ans<=m;
}
inline void solve() {
cin>>n>>m;
int minsize=n-2*m;
for(int i=0;i<n;++i) cnt[i]=0;
for(int i=1;i<=n;++i) {
cin>>a[i];
cnt[(i-a[i]+n)%n]+=1;
}
v.clear();
for(int i=0;i<n;++i) {
if(cnt[i]>=minsize&&check(i)) v.emplace_back(i);
}
cout<<v.size();
for(int i:v) cout<<' '<<i;
cout<<'\n';
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int T=1;
cin>>T;
while(T--) solve();
return 0;
} F. Pairwise Modulo
的下标大小关系不确定,不方便理解,一般的套路拆分成两个公式:
1.
2.
尝试去掉取余来对公式变形:
1.
考虑公式后面的一部分,可以发现对大于等于
的数
的贡献是
,所以可以把所有树状数组下标为
的位置加上
,然后前面所有
对
的贡献就是树状数组区间
的和了。
2.
考虑公式后面的部分,其实可以枚举,然后用树状数组求区间
内有多少个数,贡献就是
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5+7,mod=998244353;
struct node{
ll t[maxn];
void add(int p,ll x) {
while(p<maxn) {
t[p]+=x;
p+=(p&-p);
}
}
ll sum(int p) {
ll res(0);
while(p>0) {
res+=t[p];
p-=(p&-p);
}
return res;
}
}A,B;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int n;
ll ans(0),pre(0);
cin>>n;
for(int i=0,x;i<n;++i) {
cin>>x;
ans+=1LL*x*i;
ans+=A.sum(x);
ans+=pre;
pre+=x;
for(int j=x;j<maxn;j+=x) {
int l=j,r=min(j+x-1,maxn-1);
ans-=(B.sum(r)-B.sum(l-1))*j;
A.add(l,-x);//log maxn
}//log maxn
B.add(x,1);
cout<<ans<<' ';
}//n
cout<<'\n';
return 0;
} 
京公网安备 11010502036488号