\[2019.11.7解题报告\]
node
所谓同花顺,就是指一些扑克牌,它们花色相同,而且数字连续。
如今我手里有 \(n\)张扑克牌,但它们可能并不能凑成同花顺。我如今想知道,最
少更换其中的多少张牌,我能让这 \(n\) 张牌凑成一个同花顺?ios
第一行一个整数\(n\),表示扑克牌的张数。
接下来 \(n\) 行,每行两个整数 \(a_i\) 和 \(b_i\) 。其中 \(a_i\) 表示第 \(i\) 张牌的花色,\(b_i\) 表示第
\(i\) 张牌的数字。
(注意: 这里的牌上的数字不像真实的扑克牌同样是 \(1\) 到 \(13\), 具体见数据范围)git
一行一个整数,表示最少更换多少张牌能够达到目标。函数
5 1 1 1 2 1 3 1 4 1 5
0
5 1 9 1 10 2 11 2 12 2 13
2
对于 \(30\%\) 的数据,\(n ≤ 10\)。
对于 \(60\%\) 的数据,\(n ≤ 10^5\) ,\(1 ≤ a_i ≤ 10^5\) ,\(1 ≤ b_i ≤ n\)。
对于 \(100\%\)的数据,\(n ≤ 10^5 ,1 ≤ a_i ,b_i ≤ 10\)测试
去重+离散化
贪心的选择花色最多的顺子,而后枚举每一个数字做为左端点在这个花色里能组成长度为\(n\)的顺子须要修改或者添加几张牌,记录答案便可。spa
注意:
\(1\).\(vector\)的去重方法:
先排序再使用\(unique\)函数3d
\(unique\)函数将重复的元素放到\(vector\)的尾部,而后返回指向第一个重复元素的迭代器,再用\(erase\)函数将从这个元素到最后的全部元素清除code
#include <vector> #include <cstdio> #include <iostream> #include <algorithm> using namespace std; const int N = 1e5+7; int n, ans, a[N], b[N], r; vector <int> der, num[N]; int read() { int s = 0, w = 1; char ch = getchar(); while(!isdigit(ch)) {if(ch == '-') w = -1; ch = getchar();} while(isdigit(ch)) {s = s * 10 + ch - '0'; ch = getchar();} return s * w; } int main() { n = read(); for(int i = 1; i <= n; i++) a[i] = read(), b[i] = read(), der.push_back(a[i]); sort(der.begin(), der.end()); der.erase(unique(der.begin(), der.end()), der.end()); for(int i = 1; i <= n; i++) a[i] = lower_bound(der.begin(), der.end(), a[i]) - der.begin() + 1; for(int i = 1; i <= n; i++) num[a[i]].push_back(b[i]); for(int i = 1; i <= der.size(); i++) { sort(num[i].begin(), num[i].end()); num[i].erase(unique(num[i].begin(), num[i].end()), num[i].end()); for(int j = 0; j < num[i].size(); j++) r = lower_bound(num[i].begin(), num[i].end(), num[i][j] + n - 1) - num[i].begin() - 1, ans = max(ans, r - j + 1); } cout << n - ans << endl; return 0; }
话说\(STL\)真的挺好用的感受blog
有一天,你实验室的老板给你布置的这样一个实验。
首先他拿出了两个长度为\(n\) 的数列 \(a\)和 \(b\),其中每一个 \(a_i\) 以二进制表示一个集
合。例如数字 \(5 = (101)_2\) 表示集合 \({1,3}\)。第 \(i\) 次实验会准备一个小盒子,里面装
着集合 \(a_i\) 全部非空子集的纸条。老板要求你从中摸出一张纸条,若是知足你摸出的
纸条是 \(a_i\) 的子集而不是 $a_{i−b_i} \(,\)a_{i−b_i +1}$ ,...,\(a_{i−1}\) 任意一个的子集,那么你就要 ;
反之,你就逃过一劫。
令你和老板都没有想到的是,你居然每次都逃过一劫。在庆幸之余,为了知道
这件事发生的几率,你想要算出每次实验有多少纸条能使你 排序
第一行一个数字 \(n\)。
接下来 \(n\) 行,每行两个整数,分别表示 \(a_i\) 和 \(b_i\) 。
\(n\) 行,每行一个数字,表示第 \(i\) 次实验能使你 *** 的纸条数。
3 7 0 15 1 3 1
7 8 0 4
对于 \(30\%\) 的数据,\(n,a_i ,b_i ≤ 100\)
对于 \(70\%\) 的数据,\(n,a_i ,b_i ≤ 60000\)
对于 \(100\%\) 的数据,\(n,a_i ,b_i ≤ 10^5\)
保证全部的 \(a_i\) 不重复,\(b_i < i\)
枚举每个\(a[i]\)的子集
设\(f[s]\)为\(s\)这个子集最后一次出如今哪一个\(a[i]\)当中
从\(a[1]\)到\(a[n]\)依次处理。对\(a[i]\),枚举其全部的子集\(s\),若\(f[s]>=i-b[i]\),则答案\(+1\)。同时更新\(f[s]\)
真的懒了,第一题就看了好久太浪费时间了
\(so!std:\)
#include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; const int N = 1e5+10; int n,m,f[N]; int scan(){int i=0;scanf("%d",&i);return i;} void print(int x,int t=7){ if(!t)return; print(x/2,t-1); printf("%d",x&1); } int main(){ int i,j,k,a,b; freopen("test.in","r",stdin); freopen("test.out","w",stdout); n = scan(); int t,ans; for(i=1;i<=n;i++){ a = scan();b = scan(); t = a; ans =0; do{ if(f[t] < i-b)ans++; f[t] = i; //print(t);printf("\n"); t = a&(t-1); }while(t); printf("%d\n",ans); } return 0; }
\(C\) 城全部的道路都是单向的。不一样道路之间有路口,每一个路口都有一个大楼。
有一天, 城市里的全部大楼由于不明缘由, 忽然着火了。 做为超人的你要去拯救
这些大楼。初始的时候你在 \(S\) 号楼,最后你必须到达某个有补给站的大楼,你能够
沿着单向道路行驶。你能够通过某条道路或者某个大楼若干次,通过一个大楼你就
能够消灭一个大楼的大火。每一个大楼都有一个重要程度,最后这个任务的评价分数
就是你通过的全部大楼的重要度之和(若重复通过某个大楼屡次,则不重复算分) 。
你是一个聪明的超人,你想知道,经过合理的规划路线,你此次任务能获得的
最高得分是多少。
注意,该城市的道路可能有重边或自环。
第一行包括两个整数 \(n\),\(m\),\(n\) 表示路口的个数(即大楼的个数) ,\(m\) 表示道路
的条数。
接下来 \(m\) 行,每行两个整数 \(x,y\),表示 \(x\) 到 \(y\) 之间有一条单向道路。
接下来 \(n\) 行,每行一个整数,按顺序表示每一个大楼的重要度。
接下来一行包含两个整数 \(S\) 和 \(P\),\(S\) 是出发的路口(大楼)的编号,\(P\) 是有补
给站的大楼的数量。
接下来一行 \(P\) 个整数,表示有补给站的大楼的编号。
输出一行一个整数,表示你得分的最大值。
6 7 1 2 2 3 3 5 6 2 4 4 1 2 6 6 5 10 12 8 16 1 5 1 4 4 3 5 6
47
对于 \(一、二、3\) 测试点,\(N,M ≤ 300\)
对于 \(四、五、六、七、八、九、10\) 测试点,\(N,M ≤ 3000\)
对于 \(十一、十二、1三、1四、15\) 测试点,\(N,M ≤ 500000\)。每一个大楼的重要度均为非
负数且不超过 \(4000\)。
输入数据保证你能够从起点沿着单向道路到达其中的至少一个有补给站的大
楼。
注意,输入数据中存在树和链的特殊状况
\(Tarjan\)缩点+拓扑排序找最长路
//tarjan缩点+dfs #include <cstdio> #include <iostream> using namespace std; const int N = 5e5+7; int head[N], cnt, dfn[N], low[N], tot, num, belon[N], siz[N], w[N], stac[N], top, st, p; int Head[N], n, m; bool vis[N], ok[N], okk[N], flag; long long ans, sum; struct node {int nxt, to;}e[N]; struct Node {int nxt, to;}E[N]; int read() { int s = 0, w = 1; char ch = getchar(); while(!isdigit(ch)) {if(ch == '-') w = -1; ch = getchar();} while(isdigit(ch)) {s = s * 10 + ch - '0'; ch = getchar();} return s * w; } void add(int x, int y) { E[++cnt].nxt = Head[x]; E[cnt].to = y; Head[x] = cnt; } void tarjan(int u) { int v; dfn[u] = low[u] = ++tot; stac[++top] = u, vis[u] = 1; for(int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]); else if(vis[v]) low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]) { num++; do{ v = stac[top--], vis[v] = 0; belon[v] = num, siz[num] += w[v]; if(ok[v]) okk[num] = 1; }while(v != u); } } void dfs(int x) { if(okk[x]) ans = max(ans, sum); for(int i = Head[x]; i; i = E[i].nxt) sum += siz[E[i].to], dfs(E[i].to), sum -= siz[E[i].to]; } int main() { freopen("save.in", "r", stdin); freopen("save.out", "w", stdout); n = read(), m = read(); for(int i = 1, x, y; i <= m; i++) x = read(), y = read(), e[i].nxt = head[x], e[i].to = y, head[x] = i; for(int i = 1; i <= n; i++) w[i] = read(); st = read(), p = read(); for(int i = 1, x; i <= p; i++) x = read(), ok[x] = 1; for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i); for(int i = 1; i <= n; i++) for(int j = head[i]; j; j = e[j].nxt) if(belon[i] != belon[e[j].to]) add(belon[i], belon[e[j].to]); sum += siz[belon[st]], dfs(belon[st]); cout << ans << endl; fclose(stdin); fclose(stdout); return 0; }
\(std\)
#include <cstdio> #include <cmath> #include <cstdlib> #include <cstring> #include <iostream> #include <queue> using namespace std; const int MAXN = 500100; int father[MAXN] = {0}; int dfsTime[MAXN] = {0}, linkTime[MAXN] = {0}, cct[MAXN] = {0}, st[MAXN] = {0}; bool statue[MAXN] = {0}; int nowTime = 0, cnt = 0, top = 0; int point[MAXN] = {0}, nxt[MAXN] = {0}, v[MAXN] = {0}, cur[MAXN] = {0}, tot = 0; int money[MAXN] = {0}; bool cctbar[MAXN] = {0}, bar[MAXN] = {0}; int cctmoney[MAXN] = {0}, f[MAXN] = {0}; int x[MAXN], y[MAXN], n, m, start, p; int rudu[MAXN] = {0}, able[MAXN] = {0}; inline void memorycheck() { int memory = sizeof(dfsTime) + sizeof(linkTime) + sizeof(cct) + sizeof(st) + sizeof(point) + sizeof(nxt) + sizeof(v) + sizeof(money) + sizeof(cctbar) + sizeof(bar) + sizeof(cctmoney) + sizeof(f) + sizeof(x) + sizeof(y); printf("%d\n", memory / 1024 / 1024); } inline void clear() { tot = 0; memset(point, 0, sizeof(point)); memset(nxt, 0, sizeof(nxt)); } inline void addedge(int x, int y) { tot++; nxt[tot] = point[x]; point[x] = tot; v[tot] = y; } inline void dfs(int now) { while (now) { if (!dfsTime[now]) { dfsTime[now] = linkTime[now] = ++nowTime; st[++top] = now; cur[now] = point[now]; } else { if (statue[now]) { linkTime[now] = min(linkTime[now], linkTime[v[cur[now]]]); statue[now] =false; } cur[now] = nxt[cur[now]]; } if (!cur[now]) { if (dfsTime[now] == linkTime[now]) { cnt++; while (1) { cct[st[top--]] = cnt; if (st[top + 1] == now) break; } } now = father[now]; continue; } if (!dfsTime[v[cur[now]]]) { statue[now] = true; father[v[cur[now]]] = now; now = v[cur[now]]; continue; } else if (!cct[v[cur[now]]]) linkTime[now] = min(linkTime[now], dfsTime[v[cur[now]]]); } } int main() { freopen("save.in", "r", stdin); freopen("save.out", "w", stdout); scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { scanf("%d%d", &x[i], &y[i]); addedge(x[i], y[i]); } for (int i = 1; i <= n; i++) scanf("%d", &money[i]); scanf("%d%d", &start, &p); for (int i = 1; i <= p; i++) { int x; scanf("%d", &x); bar[x] = true; } for (int i = 1; i <= n; i++) if (!dfsTime[i]) dfs(i); clear(); for (int i = 1; i <= n; i++) { cctbar[cct[i]] |= bar[i]; cctmoney[cct[i]] += money[i]; } for (int i = 1; i <= m; i++) if (cct[x[i]] != cct[y[i]]) { addedge(cct[x[i]], cct[y[i]]); rudu[cct[y[i]]]++; } queue<int> q; while (!q.empty()) q.pop(); for (int i = 1; i <= cnt; i++) if (!rudu[i]) q.push(i); able[cct[start]] = 1; int ans = 0; while (!q.empty()) { int now = q.front(); q.pop(); f[now] += cctmoney[now] * able[now]; if (cctbar[now]) ans = max(ans, f[now]); for (int temp = point[now]; temp; temp = nxt[temp]) { rudu[v[temp]]--; if (!rudu[v[temp]]) q.push(v[temp]); f[v[temp]] = max(f[v[temp]], f[now]); able[v[temp]] |= able[now]; } } printf("%d\n", ans); }
之后不想写解题报告了太浪费时间了\(wxf\)会说个人!
谢谢收看, 祝身体健康!