Codeforces India Hack2016 653ABCED
通过数:2
Rating:1288
倒数第二题是后缀数组,倒数第一题没看,哪一天再厉害一点再做吧。
A:
简单题
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
const int MAXN = 1000 + 5;
int a[MAXN], n;
vector<int>vc;
int main()
{
while(scanf("%d", &n) != EOF) {
for(int i = 0 ; i < n ; i++) scanf("%d", a + i);
sort(a, a + n);
for(int i = 0 ; i < n ; i++) vc.pb(a[i]);
vector<int>::iterator newend = unique(vc.begin(), vc.end());
vc.erase(newend, vc.end());
int ok = 0;
for(int i = 0 ; i < (int)vc.size() ; i++) {
if(i < 2) continue;
if(vc[i - 2] == vc[i] - 2 && vc[i - 1] == vc[i] - 1) {
ok = 1;
break;
}
}
if(ok) puts("YES");
else puts("NO");
}
return 0;
}
B:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 26;
#define pb push_back
vector<int>e[MAXN + 5];
int H, m;
char s1[MAXN], s2[MAXN];
int ans;
void dfs(int u, int dep)
{
if(dep == H) {
ans++;
return;
}
for(int i = 0 ; i < (int)e[u].size() ; i++) {
dfs(e[u][i], dep + 1);
}
}
int main()
{
while(scanf("%d%d", &H, &m) != EOF) {
for(int i = 0 ; i < MAXN ; i++) e[i].clear();
for(int i = 0 ; i < m ; i++) {
scanf("%s%s", s1, s2);
e[s2[0] - 'a'].pb(s1[0] - 'a');
}
ans = 0;
dfs(0, 1);
printf("%d\n", ans);
}
return 0;
}
C:
/*
最多有几个不合法点是有限的,大约4-6个
然后在这些不合法的点里,枚举它和其余点交换的情况
交换后,最多影响6个点,看一看这6个点是否合法,合法后是否6个受影响的点覆盖了原不合法的点集
*/
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
const int MAXN = 150000 + 5;
int a[MAXN], n;
vector<int>vc, e;
bool invc[MAXN];
bool valid(int u)
{
if(u == n) return true;
else if(u % 2 == 1 && a[u] >= a[u + 1]) return false;
else if(u % 2 == 0 && a[u] <= a[u + 1]) return false;
return true;
}
int solve(int mark, int i)
{
swap(a[i], a[vc[mark]]);
int ok = 1;
if(!valid(i)) ok = 0; // printf("i = %d, first ok = %d\n", i, ok);
if(i > 1 && !valid(i - 1)) ok = 0;// printf("i = %d, second ok = %d\n", i, ok);
if(!valid(vc[mark])) ok = 0;// printf("i = %d, third ok = %d\n", i, ok);
if(vc[0] > 1 && !valid(vc[mark] - 1)) ok = 0;// printf("i = %d, forth ok = %d\n", i, ok);
// puts("");
if(ok) {
if(!e.empty()) e.clear();
for(int j = -1 ; j <= 1 ; j++) {
e.pb(vc[mark] + j);
e.pb(i + j);
}
sort(e.begin(), e.end());
vector<int>::iterator newend = unique(e.begin(), e.end());
e.erase(newend, e.end());
int now = 0;
for(int j = 0 ; j < (int)e.size() ; j++) {
if(now == vc.size()) break;
if(vc[now] == e[j]) now++;
}
if(now < vc.size()) ok = 0;
}
swap(a[i], a[vc[mark]]);
return ok;
}
int main()
{
while(scanf("%d", &n) != EOF) {
if(!vc.empty()) vc.clear();
for(int i = 1 ; i <= n ; i++) scanf("%d", a + i);
memset(invc, false, sizeof invc);
for(int i = 1 ; i < n ; i++) {
if(!valid(i)) {
vc.pb(i); vc.pb(i + 1);
invc[i] = true; invc[i + 1] = true;
}
}
sort(vc.begin(), vc.end());
vector<int>::iterator newend = unique(vc.begin(), vc.end());
vc.erase(newend, vc.end());
// for(int i = 0 ; i < (int)vc.size() ; i++) printf("%d ", vc[i]);
// printf("\n");
if(vc.size() > 6) puts("0"); ///此处若写为4则WA
else {
int ans = 0;
for(int mark = 0 ; mark < vc.size() ; mark++) {
for(int i = 1 ; i <= n ; i++) {
if(invc[i]) continue;
if(solve(mark, i)) ans++;
}
}
for(int mark = 0 ; mark < vc.size() ; mark++) {
for(int j = mark + 1; j < vc.size() ; j++) {
if(solve(mark, vc[j])) ans++;
}
}
printf("%d\n", ans);
}
}
return 0;
}
D:
/*
二分快递员的载重量,然后可以知道每条边可以通行几个快递员
然后跑一遍网络流
值得注意的是最后二分判断的时候
用了循环次数而不是左右端点的差值大小来作为循环结束的条件
实现了二分次数的可控,同时保证了精度
*/
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define inf (1000000007)
#define gmin(a,b) ((a) < (b) ? (a) : (b))
#define gmax(a,b) ((a) > (b) ? (a) : (b))
typedef pair<int,LL> pii;
const int MAXN = 50 + 5;
const int MAXM = 500 + 5;
const double eps = 1e-10;
vector<pii>e[MAXN];
int n, m, x;
LL num[MAXN];
queue<int>que;
int s, t; ///源点、汇点
int d[MAXN], vis[MAXN]; ///距起点距离,访问数组
int cnt;
int head[MAXN];
struct Edge ///此邻接表少add_edge函数,需要自己添加
{
int v, flow, ne; ///用flow表示残量
Edge(){}
Edge(int _u, int _v, int _flow){v = _v, ne = head[_u]; flow = _flow;}
}edge[MAXM * 2];
void addedge(int u, int v, int w)
{
edge[cnt] = Edge(u, v, w);
head[u] = cnt++;
edge[cnt] = Edge(v, u, 0);
head[v] = cnt++;
}
bool BFS(int s, int t)
{
memset(vis, 0, sizeof(vis));
while(!que.empty()) que.pop();
vis[s] = 1;
d[s] = 0;
que.push(s);
while(!que.empty()){
int u = que.front(); que.pop();
// printf("u = %d\n", u);
for(int now = head[u] ; now != -1 ; now = edge[now].ne){
int v = edge[now].v;
if(!vis[v] && edge[now].flow > 0){
vis[v] = 1;
d[v] = d[u] + 1;
que.push(v);
}
}
}
return vis[t];
}
int DFS(int u, int a)
{
// printf("u = %d, a = %d\n", u, a);
if(u == n || a == 0)
return a;
int flow = 0, f;
for(int now = head[u] ; now != -1 ; now = edge[now].ne){
int v = edge[now].v;
if(d[v] == d[u] + 1 && (f = DFS(v, min(edge[now].flow, a)))){ ///用DFS来回溯对边进行操作
edge[now].flow -= f;
edge[now ^ 1].flow += f;
flow += f;
a -= f;
if(a == 0) break;
}
}
return flow;
}
int Dinic() ///求最大流
{
int ans = 0;
while(BFS(s, t)){
ans += DFS(s, inf); ///进入起点时,设初始流量无限大
}
return ans;
}
inline bool check(double v)
{
s = 1, t = n;
cnt = 0;
memset(head, -1, sizeof head);
for(int i = 1 ; i <= n ; i++) {
for(int j = 0 ; j < (int)e[i].size() ; j++) {
pii p = e[i][j];
LL temp = p.se / v;
// if(temp < 0) printf("v = %f, i = %d, temp = %f\n", v, i, temp);
int tmp = gmin(temp, inf);
addedge(i, p.fi, tmp);
}
}
int temp = Dinic();
// printf("v = %f, temp = %d\n", v, temp);
if(temp >= x) return true;
else return false;
}
int main()
{
while(scanf("%d%d%d", &n, &m, &x) != EOF) {
for(int i = 1 ; i <= n ; i++) e[i].clear();
int u, v;
LL w;
for(int i = 0 ; i < m ; i++) {
scanf("%d%d%I64d", &u, &v, &w);
e[u].pb(mp(v, w));
}
double left = 0, right = 1000000 + 1;
for(int i = 0 ; i < 200 ; i++) {
double mid = (right + left) / 2;
if(check(mid)) left = mid;
else right = mid;
}
printf("%.8f\n", right * x);
}
return 0;
}
E:
/*
基本抄标程
已经想到要在补图上做dfs,然后判断有几个连通子块是必须要通过节点1与全图连通的就可以
但是由于补图实在太过巨大不知道怎么处理*
标程给出一种十分简便优越做法
存储一个名叫remain的set,表示剩余的点集
每次查找remain里的点,与当前点是否有不可以相连的边
没有则算入下一次dfs的储备对象里,并且从remain中删除该节点
为了防止边访问边删除导致set出现错误的情况,先用一个临时的结构存储所有可能点,然后从结构中调用该点进行删除
*/
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
const int MAXN = 300000 + 5;
typedef pair<int,int> pii;
set<pii>forbit;
set<int>remain;
int n, m, k;
bool isok(int u, int v)
{
if(u > v) swap(u, v);
return forbit.find(mp(u, v)) == forbit.end();
}
void dfs(int u)
{
vector<int>temp; temp.clear();
for(int i : remain) if(isok(u, i)) temp.pb(i);
for(int i : temp) remain.erase(i);
for(int i : temp) dfs(i);
}
int main()
{
while(scanf("%d%d%d", &n, &m, &k) != EOF) {
forbit.clear(); remain.clear();
int deg = n - 1;
for(int i = 0 ; i < m ; i++) {
int u, v; scanf("%d%d", &u, &v);
if(u > v) swap(u, v);
forbit.insert(mp(u, v));
if(u == 1) deg--;
}
if(deg < k) {
puts("impossible");
continue;
}
for(int i = 2 ; i <= n ; i++) remain.insert(i);
int cnt = 0;
for(int i = 2 ; i <= n ; i++) {
if(remain.find(i) != remain.end() && isok(1, i)) {
dfs(i);
cnt++;
}
}
if(cnt > k) puts("impossible");
else puts("possible");
}
return 0;
}