Codeforces #304 div2 only
2015-06-27 17:02:20
【传送门】
总结:去上海前的一场比赛,当时没有打,今天来补交作业....
题目难度不大,赛中AK。
A、B水,C题没有说明正负... 被坑了2发,后来打了暴力过掉,D、E思路都不难,但是需要 coding 时间。
A题:模拟
B题:排序
C题:模拟
题意 & 思路:大意是两人玩纸牌游戏,问谁赢,或产生无限循环,直接模拟百万次即可。
#include <cstdio> #include <ctime> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB(a) push_back(a) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; int n,k1,k2; queue<int> q1,q2; int main(){ scanf("%d",&n); scanf("%d",&k1); int a; for(int i = 1; i <= k1; ++i){ scanf("%d",&a); q1.push(a); } scanf("%d",&k2); for(int i = 1; i <= k2; ++i){ scanf("%d",&a); q2.push(a); } int o = 3000000; while(--o){ if(q1.empty() || q2.empty()) break; int v1 = q1.front(); q1.pop(); int v2 = q2.front(); q2.pop(); if(v1 > v2){ q1.push(v2); q1.push(v1); } else{ q2.push(v1); q2.push(v2); } } if(o == 0){ printf("-1\n"); return 0; } printf("%d ",3000000 - o - 1); if(q1.empty()) printf("2\n"); else printf("1\n"); return 0; }
D题:欧拉筛,前缀和
题意:给出 n = a!/ b!,(1<= b <= a <= 5000000),每轮让 n 整除其一个因子 x ,变成 n / x,问最多进行几轮。
思路:显然每次除掉 n 的一个素因子。那么就是计算 n 素因子分解后每个素因子指数的和(简称素因子个数和)。
可以用欧拉筛预处理出每个数的素因子个数和,然后处理出其前缀和 sum[] 来表示阶乘的素因子个数和,那么答案就是 sum[a] - sum[b]。
#include <cstdio> #include <ctime> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB(a) push_back(a) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int MAXN = 5000000; int t; int cnt[MAXN + 10]; ll sum[MAXN + 10]; int check[MAXN + 10]; int prime[1000000]; int tot; void Pre(){ for(int i = 2; i <= MAXN; ++i){ if(!check[i]) prime[++tot] = i,cnt[i] = 1; for(int j = 1; j <= tot && i * prime[j] <= MAXN; ++j){ cnt[i * prime[j]] = cnt[i] + 1; check[i * prime[j]] = 1; if(i % prime[j] == 0) break; } } for(int i = 1; i <= MAXN; ++i) sum[i] = sum[i - 1] + cnt[i]; } int main(){ Pre(); int a,b; scanf("%d",&t); for(int o = 1; o <= t; ++o){ scanf("%d%d",&a,&b); printf("%I64d\n",sum[a] - sum[b]); } return 0; }
E题:最大流
题意:给出 n 个点,m 条边的无向图。(n <= 100 , m <= 200),第 i 个点开始有 ai 个士兵,每个士兵可以选择留守在原来的点,也可以走向相邻的点(只能走一步),然后给出 b1~bn,问能否达到第 i 个点有 bi 个士兵的状态。如果可以,则输出一个转移矩阵,m[i][j] 表示第 i 个点转移给第 j 个点 m[i][j] 个士兵。
思路:因为要输出解,所以网络流是比较好的选择。
将 1~n 号点拆点,入点为 1~n,出点 n+1 ~ 2×n,源点为0,汇点为2×n+1,源点向每个入点的边的容量为 ai,出点向汇点的边的容量为 bi 。对于 m 条输出的边,比如边 (a,b),给 a 的入点和 b 的出点建边,同时给 b 的入点和 a 的出点建边,容量为无穷。跑一遍最大流后判断总流量是否为 sum(bi),如果是,扫一遍残余网络的所有边就可以统计出转移矩阵了。
注意:坑点在于,如果 sum(ai) != sum(bi),必然不可行。
#include <cstdio> #include <ctime> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB(a) push_back(a) #define MEM(a,b) memset(a,b,sizeof(a)) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int MAXN = 410; const int MAXM = 10000; int n,m; int A[MAXN],B[MAXN]; int ans[MAXN][MAXN]; struct edge{ int u,v,next,c,f; }; struct Max_flow{ int st,ed,lev[MAXN],first[MAXN],now[MAXN],ecnt; edge e[MAXM]; void init(int a,int b){ st = a,ed = b; MEM(first,-1); ecnt = 0; } void add_edge(int u,int v,int c,int f){ e[ecnt].next = first[u]; e[ecnt].u = u; e[ecnt].v = v; e[ecnt].c = c; e[ecnt].f = f; first[u] = ecnt++; e[ecnt].next = first[v]; e[ecnt].u = v; e[ecnt].v = u; e[ecnt].c = 0; e[ecnt].f = 0; first[v] = ecnt++; } bool bfs(){ queue<int> Q; while(!Q.empty()) Q.pop(); Q.push(st); MEM(lev,-1); lev[st] = 0; while(!Q.empty()){ int x = Q.front(); Q.pop(); for(int i = first[x]; ~i; i = e[i].next){ int v = e[i].v; if(lev[v] < 0 && e[i].c > 0){ lev[v] = lev[x] + 1; Q.push(v); } } } return lev[ed] != -1; } int dfs(int p,int minf){ if(p == ed || minf == 0) return minf; for(int &i = now[p]; ~i; i = e[i].next){ int v = e[i].v; if(lev[v] == lev[p] + 1 && e[i].c > 0){ int d = dfs(v,min(e[i].c,minf)); if(d > 0){ e[i].c -= d; e[i ^ 1].c += d; return d; } } } return 0; } int dinic(){ int max_flow = 0,pl; while(bfs()){ memcpy(now,first,sizeof(first)); while((pl = dfs(st,INF)) > 0) max_flow += pl; } return max_flow; } }MF; int main(){ scanf("%d%d",&n,&m); MF.init(0,2 * n + 1); int sum = 0,sum1 = 0; for(int i = 1; i <= n; ++i) scanf("%d",A + i),sum1 += A[i]; for(int i = 1; i <= n; ++i) scanf("%d",B + i),sum += B[i]; int a,b; for(int i = 1; i <= m; ++i){ scanf("%d%d",&a,&b); MF.add_edge(a,n + b,INF,1); MF.add_edge(b,n + a,INF,1); } for(int i = 1; i <= n; ++i){ MF.add_edge(i,i + n,INF,1); MF.add_edge(0,i,A[i],0); MF.add_edge(i + n,2 * n + 1,B[i],0); } int max_flow = MF.dinic(); if(sum1 != sum || max_flow != sum){ printf("NO\n"); return 0; } for(int i = 0; i < MF.ecnt; ++i) if(MF.e[i].f){ int u = MF.e[i].u; int v = MF.e[i].v - n; ans[u][v] = INF - MF.e[i].c; } printf("YES\n"); for(int i = 1; i <= n; ++i){ printf("%d",ans[i][1]); for(int j = 2; j <= n; ++j) printf(" %d",ans[i][j]); puts(""); } return 0; }