【轉載】Linux CPU100%排查方法
A. Drink (Hdu 6743)
題目大意
給定\(n\)種飲料,每種無限瓶,每瓶飲料有水分\(x[i]\),包含\(y[i]\)卡路里。
現要求選一種飲料不斷喝,求攝入至少\(m\)水分下,得到的卡路里最小值。
解題思路
一開始沒看到只能喝一種飲料考慮DP,結果開場3分鐘就破百AC懷疑人生,他們都這麼快的嗎??
因為只能喝一種就列舉每一種飲料求最小值。
神奇的程式碼
#include <bits/stdc++.h> using namespace std; typedef long long LL; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t; cin >> t; while (t--) { int n, m; cin >> n >> m; int ans = 1e9 + 7; for (int x, y, i = 1; i <= n; ++i) { cin >> x >> y; ans = min(ans, (int)ceil(m * 1.0 / x) * y); } cout << ans << endl; } return 0; }
B. GPA (Hdu 6744)
題目大意
給你四門總分,告訴你每一門中,成績對應的績點關係,問績點最高是多少。
解題思路
就\(11^4\)種情況爆搜就好了。
神奇的程式碼
#include <bits/stdc++.h> using namespace std; typedef long long LL; double ans; double ch(int x){ if (x >= 95) return(4.3); if (x >= 90) return(4.0); if (x >= 85) return(3.7); if (x >= 80) return(3.3); if (x >= 75) return(3.0); if (x >= 70) return(2.7); if (x >= 67) return(2.3); if (x >= 65) return(2.0); if (x >= 62) return(1.7); if (x >= 60) return(1.0); return 0; } void solve(int x,int pos,double mark){ if (pos==4){ mark += ch(x); ans = max(ans, mark); return; } if (x >= 95) solve(x-95,pos+1,mark+4.3); if (x >= 90) solve(x-90,pos+1,mark+4.0); if (x >= 85) solve(x-85,pos+1,mark+3.7); if (x >= 80) solve(x-80,pos+1,mark+3.3); if (x >= 75) solve(x-75,pos+1,mark+3.0); if (x >= 70) solve(x-70,pos+1,mark+2.7); if (x >= 67) solve(x-67,pos+1,mark+2.3); if (x >= 65) solve(x-65,pos+1,mark+2.0); if (x >= 62) solve(x-62,pos+1,mark+1.7); if (x >= 60) solve(x-60,pos+1,mark+1.0); solve(x,pos+1,mark); } int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int kase; cin>>kase; for (int ii=1,m; ii <= kase; ii++) { cin>>m; ans = 0; solve(m,1,0); cout<<fixed<<setprecision(1)<<ans<<endl; } return 0; }
C. Dec (Hdu 5278)
題目大意
給定兩個正整數\(a,b\),每次操作可以讓\(a\)或\(b\)減一,直到兩個都變為一,問整個過程中,出現\(a,b\)互質的情況數的最大值。
解題思路
抽象成平面上的點,左下角\((1,1)\),初始點\((a,b)\),一次可以向左或向下走一格,\(i,j\)互質點\((i,j)\)有一個貢獻,問從\((a,b)\)到\((1,1)\)的所有路徑中,走到有貢獻點的最大值,Dp即可。預處理從(1,1)到所有點最大值。
神奇的程式碼
#include <bits/stdc++.h> using namespace std; typedef long long LL; int dp[1002][1002]; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } int main(void) { dp[1][1] = 1; for (int i = 1; i <= 1000; ++i) for (int j = 1; j <= 1000; ++j) { if ((i == 1) && (j == 1)) continue; if (i == 1) dp[i][j] = dp[i][j - 1] + (__gcd(i, j) == 1); else if (j == 1) dp[i][j] = dp[i - 1][j] + (__gcd(i, j) == 1); else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + (__gcd(i, j) == 1); } int kase; cin >> kase; for (int a, b, ii = 1; ii <= kase; ii++) { read(a); read(b); write(dp[a][b], '\n'); } return 0; }
D. Civilization (Hdu 6746)
題目大意
看原文吧,就是建城市得糧食得人口派人取工作繼續得糧食直到人口達到9問最短的時間。
解題思路
列舉建城市地點然後優先派人口到能取得糧食最多的地方工作,模擬模擬就好了。
神奇的程式碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x)
{
int s = 0, c = getchar();
x = 0;
while (isspace(c))
c = getchar();
if (c == 45)
s = 1, c = getchar();
while (isdigit(c))
x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s)
x = -x;
}
template <typename T>
void write(T x, char c = ' ')
{
int b[40], l = 0;
if (x < 0)
putchar(45), x = -x;
while (x > 0)
b[l++] = x % 10, x /= 10;
if (!l)
putchar(48);
while (l)
putchar(b[--l] | 48);
putchar(c);
}
int dis(int i, int j, int x, int y)
{
int qwq = abs(i - x) + abs(j - y);
return (int)ceil(qwq * 1.0 / 2);
}
int a[505][505];
int n;
int dx[24] = {0, -1, 0, 1, -2, -1, 0, 1, 2, -3, -2, -1, 1, 2, 3, -2, -1, 0, 1, 2, -1, 0, 1, 0};
int dy[24] = {3, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -3};
int up[9] = {0, 1 * 1 * 8, 2 * 2 * 8, 3 * 3 * 8, 4 * 4 * 8, 5 * 5 * 8, 6 * 6 * 8, 7 * 7 * 8, 8 * 8 * 8};
int solve(int x, int y)
{
vector<int> qwq;
for (int i = 0; i < 24; ++i)
{
if ((x + dx[i] <= 0) || (x + dx[i] > n) || (y + dy[i] <= 0) || (y + dy[i] > n))
continue;
qwq.push_back(a[x + dx[i]][y + dy[i]]);
}
sort(qwq.begin(), qwq.end(), greater<int>());
int cur = a[x][y];
int people = 1;
int ju = 0;
size_t len = 0;
int tot = 0;
int gg = 0;
while (people < 9)
{
gg = (int)ceil((up[people] - tot) * 1.0 / cur);
ju += gg;
tot += gg * cur;
people++;
if (len < qwq.size())
{
cur += qwq[len];
++len;
}
}
return ju;
}
int main(void)
{
int kase;
read(kase);
for (int x, y, ii = 1; ii <= kase; ii++)
{
read(n);
read(x);
read(y);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
read(a[i][j]);
int ans = 1e9 + 7;
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= n; ++j)
{
ans = min(ans, dis(i, j, x, y) + solve(i, j));
}
}
printf("%d\n", ans);
}
return 0;
}
E. Rotate (Hdu 6747)
題目大意
一個圓環由外到內分成\(n\)層,第\(i\)層被分為\(a[i]\)塊,\(a[i]\)是偶數,一半塗黑色一半塗白色,間隔塗。
現獨立旋轉每一層,每一層會等概率隨機終止一種局面,問黑色聯通塊個數的期望值。
\(a[i]\)不降。
解題思路
由於\(a[i]\)不降,塊的長度只會減小,所以第\(i+1\)層的黑塊至多與與第\(i\)層的中的一個黑塊會有接觸,這樣有接觸之間的黑塊連一條邊,它們就構成了一個森林。
對於森林,聯通塊數量 = 點數 - 邊數。
由期望的線性性質,E(聯通塊) = E(點數) - E(邊數)
而\(E(\text{點數}) = \sum\limits_{i = 1}^{n} \dfrac{a[i]}{2}\)
對於邊數,第\(i+1\)層的一個黑塊與第\(i\)層的一個黑塊會有接觸的概率是
\[\frac{ \frac{2\pi}{a[i+1]} + \frac{2\pi}{a[i]}}{2\pi} = \frac{1}{a[i+1]} + \frac{1}{a[i]} \]
由期望定義知這也是期望邊數。
再乘以它們的數量即得
\[\left( \dfrac{1}{a[i+1]} + \dfrac{1}{a[i]} \right) \dfrac{a[i]}{2} \dfrac{a[i+1]}{2} = \dfrac{a[i] + a[i+1]}{4} \]
所以\(E(\text{邊數}) = \sum\limits_{i=1}^{n-1}\dfrac{a[i] + a[i+1]}{4}\)
把\(E(\text{邊數})\)和\(E(\text{點數})\)代入化簡得
\(E(\text{聯通塊}) = \dfrac{a[1] + a[n]}{4}\)
神奇的程式碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL mo = 1e9 + 7;
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int inv4 = 250000002;
int kase;
cin >> kase;
for (int ii = 1; ii <= kase; ii++)
{
int n;
cin >> n;
int a;
cin >> a;
if (n == 1)
{
cout << a / 2 << endl;
continue;
}
else
{
int b;
for (int i = 2; i <= n; ++i)
cin >> b;
cout << (LL)(a + b) * inv4 % mo << endl;
}
}
return 0;
}
F. Matrix (Hdu 6748)
題目大意
給定以原點作為中心的四個正方形,要求從被覆蓋的整點中選出\(k\)個,它們的權值最小。一個點\((x,y)\)的權值為它到原點的曼哈頓距離乘以被正方形覆蓋的次數。
解題思路
qwq
神奇的程式碼
qwq
G. Mosquito (Hdu 6749)
題目大意
給了一個網格圖,一些邊緣網格(窗戶)有一些蚊子,蚊子每一刻可以上下左右移動一格,不能移出網格,假設網格足夠聰明,問最少過多長時間,每個網格都有至少一隻蚊子。
解題思路
首先蚊子數少於網格數就直接輸出 -1。
考慮逆向,即初始時刻每個位置都有一隻蚊子,現在蚊子要飛回窗戶,問最少過多長時間,限制就是飛回某一窗戶的蚊子數不能多餘該窗戶原有的蚊子數。
先預處理出每個位置的蚊子飛到每一個窗戶所需要的時間。
很顯然時間越長,蚊子肯定能飛回窗戶,方案可行對時間具有單調性。
二分時間,得到每個蚊子能飛到哪些窗戶,再考慮如何分配哪些蚊子飛到哪些窗戶,可以看出是帶有反悔性的決策,跑一遍網路流即可判斷是否可行。
但蚊子數太多,如果我們把每隻蚊子與能飛到的窗戶連一條邊,點數和邊數會巨大,我們考慮如何壓點。
考慮到蚊子能飛到窗戶的情況數最多隻有\(2^6\)種,於是我們把能飛到窗戶的情況相同的蚊子都壓成一個點,這樣點數就只有\((2+6+2^6)\)。
具體的連邊,就是源點與所有情況數連一條邊,容量為該情況對應的蚊子數;每種情況與對應的窗戶連一條邊,容量無限;每個窗戶與匯點連一條邊,容量是該窗戶初始有的蚊子數量。
神奇的程式碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define MIN(a, b) (((a) < (b) ? (a) : (b)))
#define MAX(a, b) (((a) > (b) ? (a) : (b)))
template <typename T>
void read(T &x)
{
int s = 0, c = getchar();
x = 0;
while (isspace(c))
c = getchar();
if (c == 45)
s = 1, c = getchar();
while (isdigit(c))
x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s)
x = -x;
}
template <typename T>
void write(T x, char c = ' ')
{
int b[40], l = 0;
if (x < 0)
putchar(45), x = -x;
while (x > 0)
b[l++] = x % 10, x /= 10;
if (!l)
putchar(48);
while (l)
putchar(b[--l] | 48);
putchar(c);
}
#define M 100
#define N 640
const int INF = 233333333;
struct data
{
int to, nxt, flow;
} line[N * 2];
int n, m, l, r, ans, team[M * 2], dis[M * 2], head[M * 2], num, u, v, st, en, qaq;
void add(int u, int v, int w)
{
num++;
line[num].nxt = head[u];
line[num].to = v;
line[num].flow = w;
head[u] = num;
num++;
line[num].nxt = head[v];
line[num].to = u;
line[num].flow = 0;
head[v] = num;
}
bool BFS()
{
int u, v;
l = r = 0;
team[++r] = st;
memset(dis, 0, sizeof(dis));
dis[st] = 1;
while (l < r)
{
u = team[++l];
for (int i = head[u]; i; i = line[i].nxt)
{
v = line[i].to;
if (dis[v] == 0 && line[i].flow)
{
dis[v] = dis[u] + 1;
team[++r] = v;
}
}
}
if (dis[en])
return true;
else
return false;
}
int DFS(int u, int f)
{
if (u == en)
return f;
int tmp = 0;
int qwq = 0;
int v = 0;
for (int i = head[u]; i; i = line[i].nxt)
{
v = line[i].to;
if (dis[v] == dis[u] + 1 && line[i].flow)
{
qwq = DFS(v, MIN(f - tmp, line[i].flow));
line[i].flow -= qwq;
line[i ^ 1].flow += qwq;
tmp += qwq;
if (tmp == f)
return tmp;
}
}
return tmp;
}
int x[8], y[8], cnt[8];
int k;
int ddis[1001][1001][8];
int main(void)
{
int t;
read(t);
while (t--)
{
read(n);
read(m);
read(k);
long long qmq = 0;
for (int i = 1; i <= k; ++i)
{
read(x[i]);
read(y[i]);
read(cnt[i]);
qmq += (long long)cnt[i];
for (int a = 1; a <= n; ++a)
for (int b = 1; b <= m; ++b)
{
ddis[a][b][i] = abs(a - x[i]) + abs(b - y[i]);
}
}
if (qmq < (long long)n * m)
{
printf("-1\n");
continue;
}
int tot = (1 << (k));
st = 0;
en = tot + k + 1;
int l = 0, r = n + m;
int cc[66] = {0};
while (l < r)
{
int mid = (l + r) >> 1;
num = 1;
for (int i = st; i <= en; ++i)
head[i] = 0;
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
int sign = 0;
for (int a = 1; a <= k; ++a)
{
if (ddis[i][j][a] <= mid)
sign |= (1 << (a - 1));
}
cc[sign]++;
}
}
for (int i = 0; i < (1 << k); ++i)
{
for (int a = 1; a <= k; ++a)
if ((i >> (a - 1)) & 1)
add(i + 1, tot + a, INF);
add(st, i + 1, cc[i]);
cc[i] = 0;
}
for (int i = 1; i <= k; ++i)
add(tot + i, en, cnt[i]);
int dd = 0;
while (BFS())
dd += DFS(st, INF);
if (dd < n * m)
l = mid + 1;
else
r = mid;
}
write(r, '\n');
}
return 0;
}
H. Function (Hdu 6750)
題目大意
給定\(n\),計算\(\sum\limits_{i = 1}^{n} \sum\limits_{t|i} t [gcd(t,\dfrac{i}{t}) = 1]\)
解題思路
參考出處
化公式
從\([gcd(t,\dfrac{i}{t}) = 1] = \epsilon(gcd(t,\dfrac{i}{t})) = \sum\limits_{d|gcd(t,\frac{i}{t})} \mu(d) 1(\frac{gcd(t,\frac{i}{t})}{d}) = \sum\limits_{d|gcd(t,\frac{i}{t})} \mu(d)\)出發。
\[\begin{aligned} \sum\limits_{i = 1}^{n} \sum\limits_{t|i} t [gcd(t,\dfrac{i}{t}) = 1] &= \sum\limits_{i = 1}^{n} \sum\limits_{t|i} t \sum\limits_{d|gcd(t,\frac{i}{t})} \mu(d) \\ &= \sum\limits_{i = 1}^{n} \sum\limits_{t|i} t \sum\limits_{d|t,d|\frac{i}{t}} \mu(d) \\ 調整順序,列舉\mu(d)考慮有多少個&= \sum\limits_{d = 1}^{n} \mu(d) \sum\limits_{t = 1}^{\lfloor \frac{n}{d} \rfloor} td \lfloor \frac{n}{d^2 t} \rfloor \\ (調整順序,將最右邊的d^2t看成關於\lfloor \frac{n}{d^2 t} \rfloor的自變數)&= \sum\limits_{t = 1}^{n} \lfloor \frac{n}{t} \rfloor \sum\limits_{d^2|t} \mu(d) \frac{t}{d} \\ 調整順序&= \sum\limits_{d = 1}^{\sqrt{n}} \mu(d) \sum\limits_{t = 1}^{\lfloor \frac{n}{d^2} \rfloor} \lfloor \frac{n}{d^2t} \rfloor \frac{td^2}{d} \\ &= \sum\limits_{d = 1}^{\sqrt{n}} \mu(d)d \sum\limits_{t = 1}^{\lfloor \frac{n}{d^2} \rfloor} t \lfloor \frac{n}{d^2t} \rfloor \\ G(x) = \sum\limits_{i = 1}^{x} t \lfloor \frac{i}{t} \rfloor \to &=\sum\limits_{d = 1}^{\sqrt{n}} \mu(d)d \cdot G \left( \lfloor \frac{n}{d^2} \rfloor \right) \end{aligned} \]
\(G(x)\)可用整數分塊求,求累加和也可用整數分塊求。
至於複雜度為什麼會有log不會qwq
神奇的程式碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x)
{
int s = 0, c = getchar();
x = 0;
while (isspace(c))
c = getchar();
if (c == 45)
s = 1, c = getchar();
while (isdigit(c))
x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s)
x = -x;
}
template <typename T>
void write(T x, char c = ' ')
{
int b[40], l = 0;
if (x < 0)
putchar(45), x = -x;
while (x > 0)
b[l++] = x % 10, x /= 10;
if (!l)
putchar(48);
while (l)
putchar(b[--l] | 48);
putchar(c);
}
const LL mo = 1e9 + 7;
const LL N = 1e6 + 8;
bool visit[N];
LL prim[N];
int u[N];
LL sum_mu[N];
void pre_mu()
{
sum_mu[0] = 0;
memset(visit, false, sizeof(visit));
int tot = 0;
u[1] = 1;
sum_mu[1] = 1;
for (int i = 2; i <= N; i++)
{
if (!visit[i])
{
visit[i] = true;
prim[++tot] = i;
u[i] = -1;
}
for (int j = 1; j <= tot; j++)
{
if (prim[j] * i > N)
break;
visit[prim[j] * i] = true;
if (i % prim[j])
u[prim[j] * i] = -u[i];
else
{
u[prim[j] * i] = 0;
break;
}
}
sum_mu[i] = (sum_mu[i - 1] + (LL)u[i] * i % mo + mo) % mo;
}
}
LL inv2 = 500000004;
LL calc(LL l, LL r)
{
LL nxt = 0;
LL tmp = 0;
while (l <= r)
{
nxt = r / (r / l);
tmp = (tmp + (r / l) * ((l + nxt) % mo) % mo * ((nxt - l + 1) % mo) % mo * inv2 % mo) % mo;
l = nxt + 1;
}
return tmp;
}
int main(void)
{
pre_mu();
int kase;
read(kase);
for (int ii = 1; ii <= kase; ii++)
{
LL n;
LL ans = 0;
read(n);
LL up = sqrt(n);
LL l = 1;
LL nxt = 0;
while (l <= up)
{
nxt = (LL)sqrt(n / (n / (l * l)));
if (nxt > up)
nxt = up;
ans = (ans + calc(1, n / (l * l)) * ((sum_mu[nxt] - sum_mu[l - 1] + mo) % mo) % mo) % mo;
l = nxt + 1;
}
write(ans, '\n');
}
return 0;
}