Codeforces Round #407 (Div. 2)


链接 http://codeforces.com/contest/789


A. Anastasia and pebbles

水题,略。
注意点:如果要把1~k分为一组,k+1~2k分为1组,可以通过如下操作。
(a[i]-1) / k +1

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <cmath>
using namespace std;

#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
const int N = 105;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}

ll n,k,a[maxn],ans,cnt;

int main() {
	read(n), read(k);
	for(int i=0;i<n;i++) read(a[i]);
	for(int i=0;i<n;i++) {
		ans += (a[i]-1) / k + 1;
	}
	cout<<(ans+1)/2<<endl;
	return 0;
}


B. Masha and geometric depression

水题,略。
注意考虑q=-1,0,1的情况

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <cmath>
using namespace std;

#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
const int N = 105;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}

ll b,q,l,m,ans,x;
map<ll,ll> mp;
map<ll,ll> vis;

bool check(ll x) {
	if(abs(x)>l) return false;
	return 1;
}

int main() {
	read(b), read(q), read(l), read(m);
	for(int i=1;i<=m;i++) {
		read(x);
		mp[x]++;
	}
	while(1) {
		if(vis[b] && !mp[b]) {
			cout<<"inf"<<endl;
			return 0;
		}
		if(vis[b] && mp[b]) {
			if(q==-1 && !mp[-b]) {
				cout<<"inf"<<endl;
				return 0;
			}
			cout<<ans<<endl;
			return 0;
		}
		if(!check(b)) {
			cout<<ans<<endl;
			return 0;
		}
		if(mp[b]) {
			vis[b] = 1;
			b = b*q;
			continue;
		}
		vis[b] = 1;
		ans++;
		b = b*q;
	}	
	return 0;
}

C. Functions again

水题,略。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <cmath>
using namespace std;

#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
const int N = 105;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}

ll n,a[maxn],b[maxn],c[maxn];

int main() {
	read(n);
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1;i<=n-1;i++) {
		if(i&1) {
			b[i] = abs(a[i]-a[i+1]) + b[i-1];
			c[i] = -abs(a[i]-a[i+1]) + c[i-1];
		}
		else {
			b[i] = -abs(a[i]-a[i+1]) + b[i-1];
			c[i] = abs(a[i]-a[i+1]) + c[i-1];
		}
	}
	ll maxi = 0, mini=0;
	for(int i=1;i<=n-1;i++) {
		mini = min(mini,c[i]);
		maxi = max(maxi,c[i]);
	}
	cout<<maxi-mini<<endl;
	return 0;
}


D. Weird journey

题目

给定一个图(可能不联通),n个点m条边,一条符合规定的路径是访问m-2条边2次,剩下2条边只访问1次,问有多少个符合规定的路径。

题解

原题可以转化为:加边的时候同时加再在这两个点之间加一条边,然后去掉任意两条边,要求能访问其他边正好一次(求欧拉子图)。在不删边的情况下,很容易判断出所有点的度都是偶数,所以没有大问题。
对于删去的两条边,可以分为以下几种情况:

  1. 两条都是自环边,去掉了后满足条件;
  2. 一条自环边一条普通边,去掉了后度数为奇数的点变为2个,仍然满足欧拉回路的条件;
  3. 有公共点的两条普通边,去掉了后奇数点个数变为2,满足条件;
  4. 没有公共点的两条普通边,去掉后产生4个奇点,不满足条件。

当然了,如果原图不连通,要另当别论;
需要注意的是,原图可能出现孤点(有时候是满足条件的,结果不是0)

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <cmath>
using namespace std;

#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int inf = 0x3f3f3f3f;
const int maxn = 1000005;
const int N = 105;

inline void read(ll &x) {
    ll f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}

ll n,m,ans,cnt1,cnt2; //cnt1维护普通边,cnt2维护自环边 
ll in[maxn],fa[maxn];
bool vis[maxn]; //判断孤点
 
ll get(ll x) {
	if(x==fa[x]) return x;
	return fa[x] = get(fa[x]);
}

void join(ll x,ll y) {
	fa[get(x)] = get(y);
}

int main() {
	read(n), read(m);
	for(int i=1;i<=n;i++) fa[i] = i;
	for(int i=0;i<m;i++) {
		ll x,y;
		read(x), read(y);
		join(x,y);
		vis[x] = vis[y] = 1;
		if(x!=y) in[x]++, in[y]++;
		if(x!=y) cnt1++;
		else cnt2++;
	}
//	for(int i=1;i<=n;i++) cout<<i<<' '<<fa[i]<<endl;
	set<int> s;
	for(int i=1;i<=n;i++) {
		if(vis[i]) s.insert(get(i));
		if(s.size()>=2) {
			cout<<0<<endl;
			return 0;
		}
	}
	for(int i=1;i<=n;i++) { //两个有公共点的普通边 
		ans += in[i] * (in[i]-1) / 2;
	}
	ans += cnt1 * cnt2; //一个普通边,一个自环 
	ans += cnt2 * (cnt2-1) / 2; //两个自环 
	cout<<ans<<endl;
	return 0;
}


E. The Great Mixing

题目

有k杯饮料,它们的浓度分别为a[k]/1000,要求如何混合才能使得它们的浓度变成n/1000。 (注意:一次只能一千一千的混合)

题解

解答公式
这样化简之后,就可以建图了。
以总和建图,寻找最近的重新回到0的路线(BFS)。

注意:BFS的剪枝条件为abs(sum+a[i])>1000,因为如果存在大于1000的话,即使是对的,也可以从其他小于1000的情况递推出来。(例子:501,501,-2,n=1000)

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <cmath>
using namespace std;

#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int inf = 0x3f3f3f3f;
const int maxn = 1000005;
const int N = 105;

inline void read(int &x) {
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}

int n,k,a[maxn];
map<int,int> mp;

int bfs() {
	queue<int> q;
	q.push(0);
	while(!q.empty()) {
		int x = q.front(); q.pop();
		for(int i=0;i<k;i++) {
			int u = a[i] + x;
			if(abs(u) > 1000) continue;  
			if(!mp[u]) {
				mp[u] = mp[x] + 1;
				q.push(u);
			}
			if(u==0) return mp[u];
		}		
	}	
	return -1;
}

int main() {
	read(n), read(k);
	for(int i=0;i<k;i++) {
		read(a[i]);
		a[i] -= n;
	}
	sort(a,a+k);
	k = unique(a,a+k) - a;
	cout<<bfs()<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

总想玩世不恭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值