[CF1501] Codeforces Round #707 (Div. 2, based on Moscow Open Olympiad in Informatics)

Problemsimg

# Name
A Alexey and Train Submit Add to favourites img x5859
B Napoleon Cake Submit Add to favourites img x5579
C Going Home Submit Add to favourites img x1506
D Two chandeliers Submit Add to favourites img x95
E Matrix Sorting Submit Add to favourites img x3
F Tiles for Bathroom Submit Add to favourites img x1

这场比赛的时间就很神奇。

A Alexey and Train

模拟题

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;

const int N=1e5+5;

int T,n;
int a[N],b[N],tm[N];

int main()
{
//	freopen("1.in","r",stdin);
	int i;
	
	scanf("%d",&T);
	while(T--) {
		scanf("%d",&n);
		for(i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]);
		for(i=1;i<=n;i++) scanf("%d",&tm[i]);
		
		int ans=0;
		for(i=1;i<=n;i++) {
			ans=ans+tm[i]+a[i]-b[i-1];
			if(i==n) break;
			ans=max(ans+(b[i]-a[i]+1)/2,b[i]);
		}
		printf("%d\n",ans);
	}
	return 0;
}

B Napoleon Cake

差分一下就可以了。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;

const int N=2e5+5;

int T,n;
int a[N],c[N];

int main()
{
//	freopen("1.in","r",stdin);
	int i;
	
	scanf("%d",&T);
	while(T--) {
		scanf("%d",&n);
		for(i=0;i<=n;i++) c[i]=0;
		for(i=1;i<=n;i++) scanf("%d",&a[i]);
		for(i=1;i<=n;i++) c[max(i-a[i]+1,1)]++,c[i+1]--;
		for(i=1;i<=n;i++) c[i]+=c[i-1];
		for(i=1;i<=n;i++) printf("%d ",(c[i]>0));
		puts("");
	}
	return 0;
}

C Going Home

题意,给定 \(a_1...a_n\) ,求出四个不同的下标满足 \(x,y,z,w\) 满足 \(a_x+a_y=a_z+a_w\)

\(n \le 10^5,\max a \le 2.5 \times 10^6\)

很有意思的一道题。

\(a_x-a_z=a_w-a_y\)

刚开始我还想着用 DS 维护,发现不大行。

于是盲猜答案上界不会很大,乱证一下好像可以 \(\le \sqrt{\max a}\)

于是暴力即可。

特判掉 出现次数 \(\ge 2\) 的情况。

只要跑不死,就往死里跑。要死跑不完,就是 NO ANSWER。

#include<ctime>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;

const int N=5e6+5;

int n,m;
int a[N],c[N];

int main()
{
//	freopen("1.in","r",stdin);
	int i,j;
	int x;
	
	scanf("%d",&n);
	for(i=1;i<=n;i++) scanf("%d",&a[i]),m=max(m,a[i]);
	for(i=1;i<=n;i++) c[a[i]]++;
	
	vector<int> v;
	for(i=1;i<=m;i++) {
		if(c[i]>=4) {
			puts("YES");
			for(j=1,x=0;j<=n && x<4;j++) 
				if(a[j]==i) printf("%d ",j),x++;
			return 0;
		}
		else if(c[i]>=2) v.push_back(i);
	}
	if(v.size()>=2) {
		vector<int> ans;
		for(i=0;i<2;i++) 
			for(j=1,x=0;j<=n && x<2;j++) 
				if(a[j]==v[i]) x++,ans.push_back(j);
				
		swap(ans[0],ans[2]);
		puts("YES");
		for(i=0;i<4;i++) printf("%d ",ans[i]);
		return 0;
	}
	
	for(i=1;i<=n;i++) c[a[i]]=i;
	if(v.size()==1) {
		for(i=1;v[0]-i>=1 && i+v[0]<=m;i++) {
			if(c[v[0]-i] && c[v[0]+i]) {
				puts("YES");
				printf("%d %d ",c[v[0]-i],c[v[0]+i]);
				for(j=1,x=0;j<=n && x<2;j++) 
					if(a[j]==v[0]) printf("%d ",j),x++;
				return 0;
			}
		}	
	}
	
	vector<PII> ans;
	for(i=1;i<=m && clock()<=1.8*CLOCKS_PER_SEC;i++) {
		ans.clear();
		for(j=1;j<=n;j++) {
			if(c[a[j]]==j && a[j]>i && c[a[j]-i]) 
				ans.push_back(PII(c[a[j]-i],j));
		}
		sort(ans.begin(),ans.end());
		if(ans.size()>=3) {
			puts("YES");
			vector<int> pos;
			pos.push_back(ans[0].first),pos.push_back(ans[0].second);
			if(ans[1].first==ans[0].second) 
				pos.push_back(ans[2].first),pos.push_back(ans[2].second);
			else pos.push_back(ans[1].first),pos.push_back(ans[1].second);
			swap(pos[0],pos[2]);
			printf("%d %d %d %d\n",pos[0],pos[1],pos[2],pos[3]);
			return 0;
		}
		else if(ans.size()==2 && ans[1].first!=ans[0].second) 
			return printf("YES\n%d %d %d %d\n",ans[0].first,ans[1].second,ans[0].second,ans[1].first)&0;
	} 
	puts("NO");
	return 0;
}

D Two chandeliers

很明显的周期性质。

思路:先求出 一个周期几次 diff , 然后二分求剩下的周期。

Part 1 一个周期几次 diff

\(T=lcm(n,m)\)

本题有一个很重要的性质,就是 \(a_i\) 两两不同, \(b_j\) 两两不同,于是相同的位置就是可枚举的。

而不同的次数就是 \(T-\) 相同的次数。

这里不妨假设 下标从 \(0\) 开始,假设 \(a_i=b_j\) ,则贡献的位置 \(x\) 满足

\[x=i \pmod n \\ x=j \pmod m \]

根据中国剩余定理,\(x\)\([0,lcm(n,m))\) 有至多一解,并且若有解,周期为 \(lcm(n,m)=T\)。用 excrt 合并即可。

由于对于每个 \(a_i\) 至多有一个 \(b_j\) 与之相同,并且至多有一解,故在一个周期内至多有 \(\min(n,m)\) 个解。求出 这些解,Part 1 就做完了。

Part 2 二分求剩下的周期

不妨把 Part 1 位置存在 vector 里,则再经过 \(day\) 天的 diff 数就是

\[day-\sum_{i=0}^{v.size()-1}[v[i] \le day] \]

sort 一下,用 upper_bound 可以 \(\mathcal O(\log n)\) 求。

总的时间复杂度 (假设 \(n,m\) 同阶): \(\mathcal O(n\log n+\log^2 n)\)

Code:

注意如果最后一个周期是完整的,要特判掉。

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;

const int N=1e6+5;

LL muler(LL x,LL k,LL MOD)
{
	LL res=0; x=(x%MOD+MOD)%MOD; k=(k%MOD+MOD)%MOD; 
	while(k) {
		if(k&1) res=(res+x)%MOD;
		x=(x+x)%MOD; k>>=1;
	}
	return res%MOD;
}

LL power(LL x,LL k,LL MOD)
{
	LL res=1; x%=MOD;
	while(k) {
		if(k&1) res=muler(res,x,MOD);
		x=muler(x,x,MOD); k>>=1;
	}
	return res%MOD;
}

LL exgcd(LL a,LL b,LL& x,LL& y)
{
	if(b==0) {
		x=1; y=0;
		return a;	
	}
	LL z=exgcd(b,a%b,y,x);
	y-=a/b*x;
	return z;
}

LL inv(LL x,LL p) 
{
	LL y,z; exgcd(x,p,y,z);
	return (y%p+p)%p;  
}

LL excrt(int n,LL b[],LL a[])
{
	LL m=a[1],ans=b[1];
	for(int i=2;i<=n;i++) {
		LL y,z,d=exgcd(m,a[i],y,z);
		if((b[i]-ans)%d!=0) return -1;
		y=muler(y,(b[i]-ans)/d,a[i]/d);
		
		ans+=y*m;
		m=a[i]/d*m;
		ans=(ans%m+m)%m;
	}
	return ans;
}

LL gcd(LL a,LL b) 
{
	if(b==0) return a;
	else return gcd(b,a%b);
}

LL lcm(LL a,LL b) { return a/gcd(a,b)*b; }

int n,m;
LL kth;
int a[N],b[N],c[N];
LL A[N],B[N];
vector<LL> v;

LL calc(LL day) 
{
//	cerr<<day<<" "<<day-(upper_bound(v.begin(),v.end(),day)-v.begin())<<endl;
	if(day<=0) return 0;
	else return day-(upper_bound(v.begin(),v.end(),day)-v.begin());
}

int main()
{
//	freopen("1.in","r",stdin);
	int i,j;
	LL x;
	
	scanf("%d%d%lld",&n,&m,&kth);
	for(i=0;i<n;i++) scanf("%d",&a[i]);
	for(i=0;i<m;i++) scanf("%d",&b[i]);
	memset(c,-1,sizeof c);
	for(i=0;i<n;i++) c[a[i]]=i;
	for(i=0;i<m;i++) {
		if(~c[b[i]]) {
			j=c[b[i]];
			A[1]=n; A[2]=m;
			B[1]=j; B[2]=i;
			x=excrt(2,B,A);
			if(x==-1) continue;
			v.push_back(x+1);
//			cerr<<x<<endl;
		}
	}
	sort(v.begin(),v.end());
	LL times=lcm(n,m)-v.size();
	LL turns=(kth-1)/times;
	kth-=turns*times;
	
	LL L=-1,R=lcm(n,m),mid;
	while(L+1<R) {
		mid=(L+R)>>1;
		if(calc(mid)>=kth) R=mid;
		else L=mid;
	}
	printf("%lld\n",turns*lcm(n,m)+R);
	return 0;
}

E,F 不会 wtcl:)

posted @ 2021-03-13 22:48  cjlworld  阅读(376)  评论(0编辑  收藏  举报