Codeforces Round 943 (Div. 3)D-G

题目链接:CF链接

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时,可以遍历得cnticnti表示公共前缀长度为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';
    }

}

Codeforces Round 894 (Div. 3) 是一个Codeforces举办的比赛,是第894轮的Div. 3级别比赛。它包含了一系列题目,其中包括题目E. Kolya and Movie Theatre。 根据题目描述,E. Kolya and Movie Theatre问题要求我们给定两个字符串,通过三种操作来让字符串a等于字符串b。这三种操作分别为:交换a中相同位置的字符、交换a中对称位置的字符、交换b中对称位置的字符。我们需要先进行一次预处理,替换a中的字符,然后进行上述三种操作,最终得到a等于b的结果。我们需要计算预处理操作的次数。 根据引用的讨论,当且仅当b[i]==b[n-i-1]时,如果a[i]!=a[n-i-1],需要进行一次操作;否则不需要操作。所以我们可以遍历字符串b的前半部分,判断对应位置的字符是否与后半部分对称,并统计需要进行操作的次数。 以上就是Codeforces Round 894 (Div. 3)的简要说明和题目E. Kolya and Movie Theatre的要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Codeforces Round #498 (Div. 3) (A+B+C+D+E+F)](https://blog.csdn.net/qq_46030630/article/details/108804114)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Codeforces Round 894 (Div. 3)A~E题解](https://blog.csdn.net/gyeolhada/article/details/132491891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值