D题:
思路:比较常见的排列加转移,容易发现实际上就是几个环组成的图,
每个环上的点可以抵达环上任意点。观察数据范围可以发现,每个环的大小
不超过2e5,所以可以直接暴力遍历环,每到一个点考虑在当前点停下后的贡献。
容易知道每个点肯定是第一次到最优,贡献就是到这个点的贡献和停在这个点
之后的贡献之和,sum+a[i]*(k-cnt)。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef long long ll;
int a[N],p[N],vis[N];
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--){
int n,k,s,ss;
cin>>n>>k>>s>>ss;
for(int i=1;i<=n;i++)
cin>>p[i],vis[i]=0;
for(int i=1;i<=n;i++)
cin>>a[i];
ll maxx1=0,sum1=0,cnt=0,maxx2=0,sum2=0;
int pos=s;
while(!vis[pos]){
cnt++;
sum1+=a[pos];
vis[pos]=1;
maxx1=max(maxx1,sum1+a[pos]*(k-cnt));
if(cnt>=k)
break;
pos=p[pos];
}
for(int i=1;i<=n;i++)
vis[i]=0;
pos=ss,cnt=0;
while(!vis[pos]){
cnt++;
sum2+=a[pos];
vis[pos]=1;
maxx2=max(maxx2,sum2+a[pos]*(k-cnt));
if(cnt>=k)
break;
pos=p[pos];
}
if(maxx1>maxx2){
cout<<"Bodya"<<endl;
}
else if(maxx1<maxx2){
cout<<"Sasha"<<endl;
}
else{
cout<<"Draw"<<endl;
}
}
}
E题:
思路:一共可以得到的曼哈顿距离区间为[0,2*n-2],先将n个点填满第一行易得此时拥有
的距离集合为[0,n-1]。如果可以将[0,2*n-2]区间都包括肯定是最优解,我们考虑从第一排拆出
最后一列的那个点来增加集合大小。
由于之前已经包括了从小到大的集合,所以我们增点思路放在从2*n-2开始的从大到小集
合,也就是将拆出来的点放在(n,n)点,此时可以算出已经得到的区间为:[0,n-2] U [n,n*2-2]。
还剩下n-1的距离,我们考虑继续拆点(1,n-1),拆完之后得到区间为:[0,n-3] U [n+1,n*2-2]。
我们还需添加的距离为:n-2,n-1,n。我们可以取(n-2,n-1)为最后一个点,因为这个点与
(1,n-2)的距离为n-2,与(1,n-2)的左边点可以补齐其余两距离。
注意点:只有当n>=5时才能取完区间,小于5时特判即可。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=5e5+10;
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--){
int n;cin>>n;
if(n==2){
cout<<"1 1"<<endl<<"1 2"<<endl;
continue;
}
else if(n==4){
cout << "1 1" << endl
<<"1 3"<<endl<<"4 3"<<endl
<<"4 4"<<endl;
continue;
}
for(int i=1;i<n-1;i++)
cout<<1<<' '<<i<<endl;
cout<<n-2<<' '<<n-1<<endl;
cout<<n<<' '<<n<<endl;
}
return 0;
}
F题:
思路:求区间异或值可以利用前缀异或和。要求[l,r]区间内至少2个区间异或和相等,
分两种情况:
1.个数为奇数。
2.个数为偶数。
以上两种情况又可以简化,即个数为2或个数为3,因为两个相同数异或值为0。
当b[r]^b[l-1]==0时肯定满足条件直接输出yes;
当b[r]^b[l-1]!=0时需判断个数是为1还是3;
我们设b[r]^b[l-1]=x,那么[l,r]中应该有一个点的前缀异或和为b[r]^x,即
等于b[l-1],我们从右边取离r最近的位置,我们设为pp。若要满足条件,则
[l,pp]之间应该有一个点前缀异或和为b[l-1]^x,存在则输出yes,否则输出no。
注意点:用unordered_map会超时,卡了我半天,用map才能过。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=2e5+10;
int a[N],b[N];
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--){
map<int,vector<int> >v;
int n,q;
cin>>n>>q;
v[0].push_back(0);
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=b[i-1]^a[i];
v[b[i]].push_back(i);
}
while(q--){
int l,r;cin>>l>>r;
if((b[r]==b[l-1])){
cout << "yes\n";
continue;
}
int x=b[r]^b[l-1];
int y=x^b[r];
int p=lower_bound(v[y].begin()
,v[y].end(),r)-v[y].begin()-1;
if(v[y][p]==l-1){
cout << "no\n";
continue;
}
int pp=v[y][p];
int u=y^x;
p=lower_bound(v[u].begin(),
v[u].end(),pp)-v[u].begin()-1;
if(p<0||v[u][p]<l){
cout << "no\n";
continue;
}
cout << "yes\n";
}
cout << "\n";
}
return 0;
}
G题:
思路:由于公共前缀具有单调性,所以可以二分公共前缀长度。至于判断是否合理
可以用kmp或者z函数,但我字符串哈希wa了。G1这样就可以过了。
G2。可以发现对于划分区间的增多,lcp只会单调下降的,并且若划分了k个区间,
则lcp最多只有n/k,当k=sqrt(n)时,lcp最多也是sqrt(n)。于是我们可以从lcp长度下手,
对于前sqrt(n)个区间划分可以用G1的方法实现,对于剩余的部分则对lcp长度开始遍历。
对于lcp长度为i时,可以遍历得cnti,cnti表示公共前缀长度为i时可以划分的区间最大
为cnti。由于拥有单调性,划分区间大于i的时候,最长公共前缀长度不会大于i。
可以发现对于最长公共前缀长度是按块分布,单调减少的。
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
int cal(int n,int k,vector<int> z){
int l=1,r=n/k+1;
while(l<r){
int mid=l+r>>1;
int cnt=0;
for(int i=1;i<=n;i++){
if(z[i]>=mid){
i=i+mid-1;
cnt++;
}
}
if(cnt<k)
r=mid;
else
l=mid+1;
}
return l-1;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--){
int n,l,r;
cin>>n>>l>> r;
string s;
cin>>s;
s=' '+s;
vector<int> z(n+10);
z[1] = n;
for(int i=2,l=1,r=1;i<=n;i++){
if(i<=r) z[i]=min(z[i-l+1],r-i+1);
while(i+z[i]<=n&&s[i+z[i]]==s[1+z[i]]) ++z[i];
if(i+z[i]-1>r) l=i,r=i+z[i]-1;
}
vector<int> ans(n+10);
for(int i=1;i<=sqrt(n);i++){
int cnt=0;
for(int j=1;j<=n;j++){
if(z[j]>=i){
j+=i-1;
cnt++;
}
}
ans[cnt]=i;
}
ans[n+1]=0;
for(int i=n;i>=1;i--){
ans[i]=max(ans[i],ans[i+1]);
}
for(int i=l;i<=r;i++){
if(i<=sqrt(n))
cout<<cal(n,i,z)<<' ';
else
cout<<ans[i]<<' ';
}
cout<<'\n';
}
}