zoukankan      html  css  js  c++  java
  • 2018沈阳网络赛

    #ACM-ICPC 2018 沈阳赛区网络预赛

    D - k短路(A* + dijkstra)

    A*算法可看此博客

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    const int maxn = 1000;
    const int INF = 1000000000;
    typedef pair<int, int> PII;
    struct Anode {
    	int id, h, f;
    	Anode(int _id, int _h, int _f){id = _id, h = _h, f = _f;}
    	friend bool operator < (Anode a, Anode b) {
    		if(a.f != b.f)return a.f > b.f;
    		return a.h > b.h;
    	}
    };
    vector<PII>G[maxn + 5], rG[maxn + 5];
    int dis[maxn + 5];
    int N, M, S, E, K, T;
    void Init() {
    	for(int i = 1; i <= N; i++) {
    		G[i].clear();
    		rG[i].clear(); 
    		dis[i] = INF;
    	}
    	scanf("%d%d%d%d", &S, &E, &K, &T);
    	for(int i = 1; i <= M; i++) {
    		int u, v, w;
    		scanf("%d%d%d", &u, &v, &w);
    		G[u].push_back(PII(w, v));
    		rG[v].push_back(PII(w, u));
    	}
    }
    
    void dijkstra(int s) {
    	priority_queue<PII, vector<PII>, greater<PII> >que;
    	dis[s] = 0;
    	que.push(PII(0, s));
    	while(!que.empty()) {
    		PII p = que.top(); que.pop();
    		int v = p.second;
    		if(dis[v] < p.first)continue;
    		for(int i = 0; i < rG[v].size(); i++) {
    			int u = rG[v][i].second;
    			int w = rG[v][i].first;
    			if(dis[u] > dis[v] + w) {
    				dis[u] = dis[v] + w;
    				que.push(PII(dis[u], u));
    			}
    		}
    	}
    }
    priority_queue<Anode>que;
    int Astar(int s, int t) {
        if(dis[s] == INF)return -1;
    	while(!que.empty())que.pop();
    	que.push(Anode(s, 0, dis[s]));
    	int cur = 0;
    	while(!que.empty()) {
    		Anode p = que.top(); que.pop();
    		if(p.id == t)cur++;
    		if(cur == K)return p.h;
    		if(p.h > T)return -1;
    		for(int i = 0; i < G[p.id].size(); i++) {
    			int v = G[p.id][i].second;
    			int w = G[p.id][i].first;
    			que.push(Anode(v, p.h + w, p.h + w + dis[v]));
    		}
    	}
    	return -1;
    }
    int main() {
    	while(scanf("%d%d", &N, &M) != EOF) {
    		Init();
    		dijkstra(E);
    		int w = Astar(S, E);
    		if(w <= T && w != -1)printf("yareyaredawa
    ");
    		else printf("Whitesnake!
    ");
    	}
    	return 0;
    }
    

    F - 网络流上下界 (预处理 + 网络流最大流 ) 判断是否满流

    【题目大意】
    给你一个二分图,问你是否能删掉一些边使得所有点的度都在[L,R]区间内。

    【思路】

    首先可以处理出每个点的度为多少,然后分三种情况:
    Min_ind, Max_ind 分别代表所有点中最小的度和最大的度。

    • 如果Min_ind < L的话就一定不会满足。

    • 如果Min_ind >= L && Max_ind <= R 的话就已经满足了。

    • 如果Max_ind > R的话就是我们需要考虑的问题了。

    首先对于所有的边,假如它连接的两个点ind[u]>R&&ind[v]>R的话就可以给他删掉,因为这样不影响满足条件的点,如果ind[u]<=R&&ind[v]<=R那么这条边就不用管,因为已经是满足条件的边了。现在设度大于R的记为集合A,其余的记为集合B,那么对于ind[u],ind[v]一个在A集合,一个在B集合的这种我们给他建上边,权值为1。然后对所有A集合中的点建立一个源点,边的权值就为ind[]-R,可看为需要减少的量,然后对于B集合全部指向一个汇点,边权即为ind[]-L,可看为最多能够减少的量。现在要求的就是看所有的从源点出发的流的和是否全部能流向汇点,即该图是否为满流。

    【代码】

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    const int maxn = 40000;
    const int INF = 1000000000;
    struct edge {
    	int to, cap, rev;
    	edge(int _to, int _cap, int _rev) {
    		to = _to, cap = _cap, rev = _rev;
    	}
    };
    int N, M, K, L, R;
    vector<edge>G[maxn + 5];
    int u[maxn + 5], v[maxn + 5];
    int dep[maxn + 5], ind[maxn + 5], iter[maxn + 5];
    bool vis[maxn + 5];
    void add_edge(int from, int to, int cap) {
    	G[from].push_back(edge(to, cap, G[to].size()));
    	G[to].push_back(edge(from, 0, G[from].size() - 1));
    }
    void Init() {
    	memset(ind, 0, sizeof(ind));
    	scanf("%d%d", &L, &R);
    	for(int i = 1; i <= K; i++) {
    		scanf("%d%d", &u[i], &v[i]);
    		v[i] += N;
    		ind[u[i]]++;
    		ind[v[i]]++;
    	}
    
    }
    void bfs(int s) {
    	memset(dep, -1, sizeof(dep));
    	queue<int>que;
    	dep[s] = 0;
    	que.push(s);
    	while(!que.empty()) {
    		int v = que.front(); que.pop();
    		for(int i = 0; i < G[v].size(); i++) {
    			edge &e = G[v][i];
    			if(e.cap > 0 && dep[e.to] < 0) {
    				dep[e.to] = dep[v] + 1;
    				que.push(e.to);
    			}
    		}
    	}
    }
    
    int dfs(int v, int t, int f) {
    	if(v == t)return f;
    	for(int &i = iter[v]; i < G[v].size(); i++) {
    		edge &e = G[v][i];
    		if(e.cap > 0 && dep[v] < dep[e.to]) {
    			int d = dfs(e.to, t, min(f, e.cap));
    			if(d > 0) {
    				e.cap -= d;
    				G[e.to][e.rev].cap += d;
    				return d;
    			}
    		}
    	}
    	return 0;
    }
    int Dinic(int s, int t) {
    	int flow = 0;
    	for(;;) {
    		bfs(s);
    		if(dep[t] < 0)return flow;
    		memset(iter, 0, sizeof(iter));
    		int f;
    		while((f = dfs(s, t, INF)) > 0)flow += f;
    	}
    }
    void solve() {
    	for(int i = 0; i <= N + M + 1; i++)G[i].clear();
    	int Max_ind = 0, Min_ind = N;
    	for(int i = 1; i <= N + M; i++) {
    		Max_ind = max(Max_ind, ind[i]);
    		Min_ind = min(Min_ind, ind[i]);
    	}
    	if(Min_ind >= L) {
    		if(Max_ind <= R)printf("Yes
    ");
    		else {
    			int s = 0, t = N + M + 1, sum = 0;
    			memset(vis, 0, sizeof(vis));
    			for(int i = 1; i <= K; i++) {
    				if(ind[u[i]] > R && ind[v[i]] > R) {
    					ind[u[i]]--;
    					ind[v[i]]--;
    					vis[i] = 1;
    				}
    			}
    			for(int i = 1; i <= K; i++) {
    				if(vis[i] == 0) {
    					if(ind[u[i]] > R && ind[v[i]] > L)add_edge(u[i], v[i], 1);
    					else if(ind[v[i]] > R && ind[u[i]] > L)add_edge(v[i], u[i], 1);
    				}
    			}
    			for(int i = 1; i <= N + M; i++) {
    				if(ind[i] > R) {
    					add_edge(s, i, ind[i] - R);
    					sum += ind[i] - R;
    				}
    				else if(ind[i] > L)add_edge(i, t, ind[i] - L);
    			}
    			int res = Dinic(0, N + M + 1);
    			if(res == sum)printf("Yes
    ");
    			else printf("No
    ");
    		}
    	}
    	else printf("No
    ");
    }
    int main() {
    	int cas = 0;
    	while(~scanf("%d%d%d", &N, &M, &K)) {
    		Init();
    		printf("Case %d: ", ++cas);
    		solve();
    	}
    }
    
    

    G - 数学 、拆分质数、奇偶容斥

    【题目大意】
    已知egin{equation}a_n=
    left{egin{aligned}
    0,quad n=0
    1,quad n=1
    dfrac{3a_{n-1}-a_{n-2}}{2}+n+1,n>1
    end{aligned}
    ight.
    end{equation}
    i=1pabisum_{i=1}^pa_{b_i},其中bib_i与m互质且1bin1leq b_ileq n

    【思路】
    通过打表可以发现an=n(n+1)a_n=n*(n+1),所以先可以求出所有的小于n的数,通过推导12+23+34++n(n+1)=1*2+2*3+3*4+cdots+n*(n+1)=
    11+22+33++nn+1+2+3++n=1*1+2*2+3*3+cdots+n*n+1+2+3+cdots+n=
    n(n+1)(2n+1)/6+n(n+1)/2=n*(n+1)*(2*n+1)/6+n*(n+1)/2=
    n(n+1)(n+2)/3n*(n+1)*(n+2)/3
    可算出所有小于n的数的和。
    然后要去除所有与m不互质的数,那么可以筛出所有m的不同质因子,然后通过减掉某个因子的倍数,通过容斥,奇加偶减,即奇数个质因子就减,偶数个就加,因为对于一个因子为x,即求所有小于m的x倍数的项,求法如下
    x(x+1)+x*(x+1)+cdots假设有len项,即可化为
    xxlen(len+1)(2len+2)/6+xlen(len+1)/2x*x*len*(len+1)*(2*len+2)/6+x*len*(len+1)/2.
    具体见代码
    【代码】

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    const LL Pt = 1e9 + 7;
    const int maxn = 10000;
    LL P, P2, P3;
    int prime[maxn + 5], vis[maxn];
    LL n;
    int m, tot;
    vector<int>vec;
    LL qwe(LL x, LL y) {
        LL t = 1;
        while(y > 0) {
            if(y & 1)t = t * x % Pt;
            x = x * x % Pt;
            y >>= 1;
        }
        return t;
    }
    void Init() {
        for(int i = 2; i <= maxn; i++) {
            if(!vis[i]) {
                prime[++tot] = i;
                for(int j = i * 2; j <= maxn; j += i)vis[i] = 1;
            }
        }
    }
    void Getvec() {
        int x = m;
        for(int i = 1; prime[i] <= sqrt(x); i++) {
            if(x % prime[i] == 0) {
                vec.push_back(prime[i]);
                while(x % prime[i] == 0)x /= prime[i];
            }
        }
        if(x > 1)vec.push_back(x);
    }
    void solve() {
    	LL res = n * (n + 1) % Pt * (n + 2) % Pt * P % Pt;
    	int t = vec.size();
    	for(int j = 1; j < (1 << t); j++) {
    		LL cur = 1;
    		int cnt = 0;
    		for(int k = 0; k < t; k++) {
    			if(j & (1 << k)) {
    				cur *= vec[k];
    				cnt++;
    			}
    		}
    		LL l = n / cur;
    		LL tmp = l * (l + 1) % Pt * (2 * l + 1) % Pt * P2 % Pt;
    		tmp = tmp * cur % Pt * cur % Pt;
    		tmp = (tmp + cur * l % Pt * (l + 1) % Pt * P3 % Pt) % Pt;
    		if(cnt & 1)res = ((res - tmp) % Pt + Pt) % Pt;
    		else res = (res + tmp) % Pt;
    	}
    	printf("%lld
    ", res);
    }
    int main() {
    	Init();
    	P = qwe(3, Pt - 2);
    	P2 = qwe(6, Pt - 2);
    	P3 = qwe(2, Pt - 2);
    	while(scanf("%lld%d", &n, &m) != EOF) {
    		vec.clear();
    		Getvec();
    		solve();
    	}
    	return 0;
    }
    

    I - 模拟

    【题目大意】
    题意大概就是给你一串密文然你通过它给你的规则解码。
    具体规则就是给你的字符串每一位都是一个十六进制,首先然你将起变为01串,之后每九位看做一串,这九位中第九位为奇偶校验位,就是前八位如果有奇数个1那么第九位应该得为0,反之得为1,如果满足这个条件该九位01串的前八位就加入到真正解密的串中。然后给你一些前缀不同的01串且每个01串对应一个字符,最后你要输出明文。

    直接上代码了:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<string>
    #include<algorithm>
    #include<map>
    using namespace std;
    const int maxn = 200000;
    map<string, int>vis;
    char s[maxn + 5];
    int m, n, tot, ch;
    string f[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
    int main() {
    	int T; scanf("%d", &T);
    	while(T--) {
    		vis.clear();
    		tot = 0;
    		scanf("%d%d", &m, &n);
    		for(int i = 1; i <= n; i++) {
    			scanf("%d%s", &ch, s);
    			vis[s] = ch;
    		}
    		scanf("%s", s);
    		int len = strlen(s);
    		string str = "";
    		for(int i = 0; i < len; i++) {
    			if(s[i] >= '0' && s[i] <= '9')str += f[s[i] - '0'];
    			else if(s[i] >= 'A' && s[i] <= 'Z')str += f[s[i] - 'A' + 10];
    			else str += f[s[i] - 'a' + 10];
    		}
    		string sttr = "";
    		string tmp;
    		len = str.size();
    		for(int i = 0; i + 8 < len; i += 9) {
    			int cnt = 0; tmp = "";
    			for(int j = 0; j <= 7; j++) {
    				if(str[i + j] == '1')cnt++;
    				tmp += str[i + j];
    			}
    			cnt %= 2;
    			if(cnt ^ (str[i + 8] - '0') == 0)continue;
    			sttr += tmp;
    		}
    		//cout << sttr << endl;
    		len = sttr.size();
    		tmp = "";
    		for(int i = 0; i < len; i++) {
    			tmp += sttr[i];
    			if(vis[tmp])s[++tot] = vis[tmp], tmp = "";
    			if(tot == m)break;
    		}
    		for(int i = 1; i <= m; i++)printf("%c", s[i]); printf("
    ");
    	}
    	return 0;
    }
    

    K - 打表,找规律

    【题目大意】
    给你一个n要你找到一个最大的x满足x的每一个字串(不要求连续)都是质数或者是1。
    通过打表可发现最大的一个满足条件的为317,且满足条件的数不多。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <set>
    #include <map>
    #include <string>
    #include <cmath>
    #include <cstdlib>
    #include <ctime>
    #include <stack>
    using namespace std;
    #define debug(x) std::cerr << #x << " = " << (x) << std::endl
    typedef pair<int, int> PII;
    typedef long long LL;
    typedef unsigned long long ULL;
    
    char s[105];
    int vis[1005];
    
    int main(){
    	int len,pos,T;
    	for(int i = 1;i <= 999;i++) vis[i] = 0;
    	vis[2] = 2;vis[3] = 3;vis[5] = 5;vis[7] = 7;
    	vis[11] = 11;vis[13] = 13;vis[17] = 17;vis[23] = 23;vis[31] = 31;
    	vis[37] = 37;vis[53] = 53;vis[71] = 71;vis[73] = 73;
    	vis[113] = 113;vis[131] = 131;vis[137] = 137;vis[173] = 173;
    	vis[311] = 311;vis[317] = 317;
    	for(int i = 2;i <= 999;i++) vis[i] = max(vis[i],vis[i - 1]);
    	while(~scanf("%d",&T)){
    		for(int cas = 1;cas <= T;cas++){
    			scanf("%s",s + 1);
    			len = strlen(s + 1);
    			if(len >= 4) pos = 317;
    			else{
    				pos = 0;
    				for(int i = 1;i <= len;i++){
    					pos *= 10;
    					pos += (int)(s[i] - '0');
    				}
    			}
    			printf("Case #%d: ",cas);
    			printf("%d
    ",vis[pos]);
    		}
    	}
        return 0;
    }
    
  • 相关阅读:
    JS笔记之第七天
    JS笔记之第六天
    JS笔记之第五天
    JS笔记之第四天
    JS笔记之第三天
    JS笔记之第二天
    JS笔记之第一天
    PHP文件上传
    bit、Byte、bps、Bps、pps、Gbps的单位的说明及换算
    Redis初级安装及使用
  • 原文地址:https://www.cnblogs.com/TRDD/p/9813502.html
Copyright © 2011-2022 走看看