Codeforces Round #153 (Div. 1)

A:http://www.codeforces.com/contest/251/problem/A

求满足最大差值不大于d的3点集合的个数,枚举任意点做为最小值,然后二分找到可以作为另外两点的点有几个即可。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<math.h>
#include<string>
#include<map>
#include<set>
#include<iostream>
using namespace std;
typedef long long ll;
const int inf = 1 << 29;

int a[100010];
int main()
{
	int n,d;
	scanf("%d%d",&n,&d);
	for(int i=0;i<n;i++)
		scanf("%d",&a[i]);
	ll sum=0;
	for(int i=0;i<n;i++){
		int x=a[i]+d;
		int left=0,right=n-1,mid,ans=-1;
		while(left<=right){
			mid=(left+right)>>1;
			if(a[mid]<=x){
				left=mid+1;
				ans=mid;
			}else{
				right=mid-1;
			}
		}
		if(ans>i+1){
			sum+=(ll)(ans-i)*(ans-i-1)/2;
		}
	}
	printf("%I64d\n",sum);
}

B: http://www.codeforces.com/contest/251/problem/B

很容易发现两种操作是互相抵消的,那么当一种操作连续做i次(k-i)%2能变成目标排列时,必然可以通过k次操作达到目标排列。问题要求未达到k次的时候不能变成目标排列,就要注意一种特殊情况:例如k=3,一次heads或tails都会变成目标排列,要输出NO

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<math.h>
#include<string>
#include<map>
#include<set>
#include<iostream>
using namespace std;
typedef long long ll;
const int inf = 1 << 29;

int q[110],s[110],p[110],t[110];
int check(int n)
{
	for(int i=1;i<=n;i++){
		if(p[i]!=s[i]) return 0;
	}
	return 1;
}
int main()
{
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%d",&q[i]);
	}
	for(int i=1;i<=n;i++)
		scanf("%d",&s[i]);
	for(int i=1;i<=n;i++)
		p[i]=i;
	int flag=0;
	if(check(n)){
		printf("NO\n");
		return 0;
	}
	int tmp=0;
	for(int i=1;i<=k&&flag==0;i++){
		for(int j=1;j<=n;j++){
			t[j]=p[q[j]];
		}
		for(int j=1;j<=n;j++){
			p[j]=t[j];
		}
		if(check(n)){
			if((k-i)%2==0){
				if(i==1&&k!=1)tmp=1;
				else flag=1;
			}
			break;
		}
	}
	for(int i=1;i<=n;i++)
		p[i]=i;
	for (int i = 1; i <= k&&flag==0 ; i++) {

		for (int j = 1; j <= n; j++) {
			t[q[j]] = p[j];
		}

		for (int j = 1; j <= n; j++){
			p[j] = t[j];
		}
		if(i==1&&tmp==1&&(!check(n))){
			flag=1;break;
		}
		if (check(n) && (k - i) % 2 == 0) {
			if ((k - i) % 2 == 0){
				if(i==1&&k!=1){
					if(!tmp) flag=1;
				}else flag=1;
			}
			break;
		}
	}
	if(flag) printf("YES\n");
	else printf("NO\n");

}

C: http://www.codeforces.com/contest/251/problem/C

求2到k的最小公倍数c,a->b的过程一定是a->ci->cj->b,ci,cj为c的倍数取一下余就是a%c->0 + c->0(多次)+c->b%c;c最大为360360,dp即可求解

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<math.h>
#include<string>
#include<map>
#include<set>
#include<iostream>
using namespace std;
typedef long long ll;
const int inf = 1 << 29;

int gcd(int a,int b){
	return b?gcd(b,a%b):a;
}

#define N 400000
int dp[N],k;
int solve(ll a,ll b)
{
	fill(dp,dp+N,inf);
	dp[0]=0;
	for(int i=1;i<=a-b;i++){
		dp[i]=min(dp[i],dp[i-1]+1);
		for(int j=2;j<=k;j++){
			if(i-(b+i)%j>=0)
				dp[i]=min(dp[i],dp[i-(b+i)%j]+1);
		}
	}
	return dp[a-b];
}
int main()
{
	ll a,b;
	int c=1;
	scanf("%I64d%I64d%d",&a,&b,&k);
	for(int i=2;i<=k;i++) c=c*i/gcd(c,i);
	if(a/c==b/c){
		printf("%d\n",solve(a,b));
	}else{
		printf("%I64d\n",(ll)(a/c-b/c-1)*solve(c,0)+solve(a%c,0)+solve(c,b%c));
	}
}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值