链接:HDU6772 Lead of Wisdom
#include
using namespace std;
int T;
int n, k;
struct Item
{
int a, b, c, d;
int t;
Item(int t, int a, int b, int c, int d): t(t), a(a), b(b), c(c), d(d) {}
};
vector<Item> tmp[57];
vector<Item> typ[57];
int cur;
long long ans;
void dfs(int t, int a, int b, int c, int d)
{
if (t == cur)
{
long long now = (long long)(100 + a) * (100 + b) * (100 + c) * (100 + d);
ans = max(ans, now);
return;
}
for (int i = 0; i < typ[t].size(); ++i)
{
int na = a + typ[t][i].a;
int nb = b + typ[t][i].b;
int nc = c + typ[t][i].c;
int nd = d + typ[t][i].d;
dfs(t + 1, na, nb, nc, nd);
}
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> T;
while (T--)
{
ans = 0;
cin >> n >> k;
int t, a, b, c, d;
for (int i = 1; i <= n; ++i)
{
cin >> t >> a >> b >> c >> d;
Item it(t, a, b, c, d);
tmp[t].push_back(it);
}
cur = 1;
for (int i = 1; i <= k; ++i)
{
if (tmp[i].size())
{
typ[cur++] = tmp[i];
tmp[i].clear();
}
}
dfs(1, 0, 0, 0, 0);
cout << ans << endl;
}
return 0;
}
链接:HDU6768 The Oculus
齐肯多夫 ( Z e c k e n d o r f ) (Zeckendorf) (Zeckendorf) 定理:任何正整数都可以表示成若干个不连续的斐波那契数(不包括第一个斐波那契数)之和
利用同余的性质,直接计算
#include
using namespace std;
const int MAXN = 2e6 + 7;
unsigned long long fib[MAXN];
void getfib()
{
fib[0] = 1; fib[1] = 2;
for (int i = 2; i < MAXN; ++i)
{
fib[i] = fib[i - 1] + fib[i - 2];
}
}
int T;
long long a, b ,c;
inline unsigned long long input()
{
int len;
unsigned long long res = 0;
cin >> len;
bool tmp = false;
for (int i = 0; i < len; ++i)
{
cin >> tmp;
if (tmp)
res += fib[i];
}
return res;
}
void solve()
{
a = input();
b = input();
c = input();
unsigned long long ans = a * b;
int pos = 0;
for (; c + fib[pos] != ans; ++pos);
cout << (pos + 1) << endl;
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
getfib();
cin >> T;
while (T--)
{
solve();
}
return 0;
}
链接:HDU6763 Total Eclipse
比赛的时候想到并查集了,可惜只在想并查集的删除操作
#include
using namespace std;
const int MAXN = 1e5 + 5;
struct DSU
{
int parent[MAXN];
int n; // Nums of Nodes
int cnt; // Count Strongly Connected Components
void init_parent(int n)
{
this -> n = n;
cnt = 0;
for (int i = 1; i <= n; ++i)
parent[i] = i;
}
int find_parent(int x)
{
if (parent[x] == x)
return x;
else
parent[x] = find_parent(parent[x]);
return parent[x];
}
bool check_unicom(int x, int y)
{
return find_parent(x) == find_parent(y);
}
void merge(int x, int y)
{
int parent_x = find_parent(x);
int parent_y = find_parent(y);
if (parent_x != parent_y)
{
parent[parent_x] = parent_y;
cnt++;
}
}
}dsu;
int T;
int n, m;
long long ans;
int val[MAXN];
int id[MAXN];
vector<int> graph[MAXN];
bool vis[MAXN];
int frm[MAXN]; // from which Node's Val
bool cmp(int x, int y)
{
return val[x] > val[y];
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> T;
while (T--)
{
memset(vis, 0 ,sizeof(vis));
memset(frm, 0, sizeof(frm));
ans = 0;
val[0] = 0;
cin >> n >> m;
dsu.init_parent(n);
for (int i = 1; i <= n; ++i)
{
cin >> val[i];
id[i] = i;
graph[i].clear();
}
int u, v;
for (int i = 0; i < m; ++i)
{
cin >> u >> v;
graph[u].push_back(v);
graph[v].push_back(u);
}
sort(id + 1, id + n + 1, cmp);
for (int i = 1; i <= n; ++i)
{
int now = id[i];
vis[now] = true;
for (int j = 0; j < graph[now].size(); ++j)
{
int nxt = graph[now][j];
if ((!vis[nxt]) || dsu.check_unicom(nxt, now))
continue;
frm[dsu.find_parent(nxt)] = now;
dsu.merge(nxt, now);
}
}
for (int i = 1; i <= n; ++i)
ans += (long long)(val[i] - val[frm[i]]);
cout << ans << endl;
}
return 0;
}
链接:HDU6774 String Distance
想到了 L C S + D P LCS + DP LCS+DP 可惜不会
编辑距离 a n s = l e n ( A l → r ) + l e n ( B ) − L C S ( A l → R , B ) ans = len(A_{l \to r}) + len(B) - LCS(A_{l \to R}, \ B) ans=len(Al→r)+len(B)−LCS(Al→R, B)
显然需要通过 D P DP DP 求解,问题在于 L e n ( A l → r ) Len(A_{l \to r}) Len(Al→r) 可能很大,若每次均对两个字符串 D P DP DP 必然超时
观察到, L e n ( B ) ≤ 20 Len(B) \le 20 Len(B)≤20 那么是否存在一种思路只对于 B B B 即可求得所需的 L C S LCS LCS
首先预处理出 A i → n A_{i \to n} Ai→n 中每一个小写字母出现的最靠前的位置 p o s [ i ] [ c h a r ] pos[i][char] pos[i][char]
对于每次询问,我们建立一种状态 d p [ i ] [ j ] = p o s dp[i][j] = pos dp[i][j]=pos ,指在 B 1 → i B_{1 \to i} B1→i 的子串中,满足长度为 j j j 的 L C S LCS LCS 的末尾下标的位置 p o s pos pos 中最靠前的一个
个人认为难点在于状态的设计,设计好了状态,状态转移方程并不难理解
状态转移方程
状态 | 状态 | 方程 |
---|---|---|
d p [ i ] [ j ] = p o s dp[i][j] = pos dp[i][j]=pos | d p [ i + 1 ] [ j ] dp[i + 1][j] dp[i+1][j] | d p [ i + 1 ] [ j ] = d p [ i ] [ j ] dp[i + 1][j] = dp[i][j] dp[i+1][j]=dp[i][j] |
d p [ i ] [ j ] = p o s dp[i][j] = pos dp[i][j]=pos | d p [ i + 1 ] [ j + 1 ] dp[i + 1][j + 1] dp[i+1][j+1] | d p [ i + 1 ] [ j + 1 ] = p o s [ d p [ i ] [ j ] + 1 ] [ b [ i + 1 ] ] dp[i + 1][j + 1] = pos[ \ dp[i][j] + 1 \ ][ \ b[i + 1] \ ] dp[i+1][j+1]=pos[ dp[i][j]+1 ][ b[i+1] ] |
# include
using namespace std;
const int MAXN = 1e5 + 7;
int T;
int n, m;
string stra, strb;
int a[MAXN];
int b[30];
int q;
int l, r;
int pos[MAXN][30];
int dp[30][30];
int ans;
void pre()
{
n = stra.length();
m = strb.length();
for (int i = 0; i < n; ++i)
{
a[i + 1] = stra[i] - 'a';
}
for (int i = 0; i < m; ++i)
{
b[i + 1] = strb[i] - 'a';
}
memset(pos[n + 1], 0x3f, sizeof(pos[n + 1]));
for (int i = n; i > 0; --i)
{
for (int j = 0; j < 26; ++j)
{
pos[i][j] = pos[i + 1][j];
}
pos[i][a[i]] = i;
}
}
int solve()
{
memset(dp, 0x3f, sizeof(dp));
dp[0][0] = l - 1;
for (int i = 0; i < m; ++i)
{
for (int j = 0; j <= i; ++j)
{
if (dp[i + 1][j] > dp[i][j])
dp[i + 1][j] = dp[i][j];
if (dp[i][j] < r && dp[i + 1][j + 1] > pos[dp[i][j] + 1][b[i + 1]])
// dp[i + 1][j] is incorrect
dp[i + 1][j + 1] = pos[dp[i][j] + 1][b[i + 1]];
}
}
for (int j = m; j > 0; --j)
{
for (int i = m; i >= j; --i)
{
if (dp[i][j] <= r)
return j;
}
}
return 0;
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> T;
while (T--)
{
cin >> stra >> strb;
pre();
cin >> q;
while (q--)
{
cin >> l >> r;
ans = r - l + 1 + m - 2 * solve();
cout << ans << endl;
}
}
return 0;
}
链接:HDU6767 New Equipments
给定 n n n 个工人, m m m 件物品 ( 1 ≤ n ≤ 50 , n ≤ m ≤ 1 0 8 ) (1 \le n \le 50, n \le m \le 10^8) (1≤n≤50,n≤m≤108)
每个工人选择第 j j j 件物品需要付工资 a i ⋅ j 2 + b i ⋅ j + c i a_i \cdot j^2 + b_i \cdot j + c_i ai⋅j2+bi⋅j+ci,物品不能重复使用
求最小的工资之和
资本家的丑恶而嘴脸
建图的思想比较重要,剩下来的算法抄板子就行
#include
using namespace std;
#define int long long
const int MAXN = 1e4 + 7;
const int MAXE = 1e5 + 7;
const long long INF = 1e18 + 7;
struct MCMF_SPFA
{
struct Edge
{
int v, cap, cost, nxt;
} edge[MAXE << 1];
int cntedge, sumflow;
int head[MAXN];
void init()
{
cntedge = 0;
memset(head, -1, sizeof(head));
}
void addEdge(int u, int v, int cap, int cost)
{
edge[cntedge].v = v;
edge[cntedge].cap = cap;
edge[cntedge].cost = cost;
edge[cntedge].nxt = head[u];
head[u] = cntedge++;
edge[cntedge].v = u;
edge[cntedge].cap = 0;
edge[cntedge].cost = -cost;
edge[cntedge].nxt = head[v];
head[v] = cntedge++;
}
int dis[MAXN], pre[MAXN];
bool vis[MAXN];
bool spfa(int s, int t, int n)
{
int u, v;
queue<int> q;
memset(vis, false, sizeof(vis));
memset(pre, -1, sizeof(pre));
for (int i = 0; i <= n; ++i)
dis[i] = INF;
vis[s] = true;
dis[s] = 0;
q.push(s);
while (!q.empty())
{
u = q.front();
q.pop();
vis[u] = false;
for (int i = head[u]; i != -1; i = edge[i].nxt)
{
v = edge[i].v;
if (edge[i].cap && dis[v] > dis[u] + edge[i].cost)
{
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if (!vis[v])
{
q.push(v);
vis[v] = true;
}
}
}
}
return dis[t] != INF;
}
void mincostmaxflow(int s, int t, int n, int num)
{
int flow = 0;
int minflow, mincost;
mincost = 0;
while (spfa(s, t, n))
{
minflow = INF + 1;
for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].v])
if (edge[i].cap < minflow)
minflow = edge[i].cap;
flow += minflow;
for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].v])
{
edge[i].cap -= minflow;
edge[i ^ 1].cap += minflow;
}
mincost += dis[t] * minflow;
cout << mincost;
if (flow < num)
cout << " ";
}
sumflow = flow;
cout << endl;
// return mincost;
}
}mcmf;
int T;
int n, m;
int a, b ,c;
int s, t;
int len; //Lens of Minumum Nums in Func
int cnt; //Count Node in NetworkFlow, node [1, n] are workers
unordered_map<int, int> mp;
void quad(int id, int a, int b, int c)
{
int ctr = - b / (2 * a);
int lft, rgt;
lft = ctr - len / 2 - 3;
rgt = lft + len - 1;
if (lft < 1)
{
rgt += 1 - lft;
lft = 1;
}
else if (rgt > m)
{
lft -= rgt - m;
rgt = m;
}
// Incorrect Pos
for (int i = lft; i <= rgt; ++i)
{
int cost = a * i * i + b * i + c;
if (!mp.count(i))
{
cnt++;
mp[i] = cnt;
mcmf.addEdge(cnt, t, 1, 0);
}
int nxt = mp[i];
mcmf.addEdge(id, nxt, 1, cost);
}
}
void solve()
{
mp.clear();
mcmf.init();
cin >> n >> m;
len = min(n + 7, m);
s = 0;
t = n * (len + 1) + 1;
cnt = n;
for (int i = 1; i <= n; ++i)
{
cin >> a >> b >> c;
mcmf.addEdge(s, i, 1, 0);
quad(i, a, b, c);
}
mcmf.mincostmaxflow(s, t, t, n);
}
int32_t main(void)
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> T;
while(T--)
{
solve();
}
}