文章目录
链接 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次,问有多少个符合规定的路径。
题解
原题可以转化为:加边的时候同时加再在这两个点之间加一条边,然后去掉任意两条边,要求能访问其他边正好一次(求欧拉子图)。在不删边的情况下,很容易判断出所有点的度都是偶数,所以没有大问题。
对于删去的两条边,可以分为以下几种情况:
- 两条都是自环边,去掉了后满足条件;
- 一条自环边一条普通边,去掉了后度数为奇数的点变为2个,仍然满足欧拉回路的条件;
- 有公共点的两条普通边,去掉了后奇数点个数变为2,满足条件;
- 没有公共点的两条普通边,去掉后产生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;
}