首先我們要先知道構成三角形需要的條件就是「最長邊
這個兩邊和很重要,因為兩邊和代表一種壓縮的可能性。
誠如題目中的 Hint ,我們可以先找到短的兩邊和為
接者可以列舉所有的長邊值,統計選定長邊的情況下,有幾種短邊的組合。
之後後面有提供第二種做法,那是直接計算在選定長邊的情況下,有幾種短邊的組合。
#include <bits/stdc++.h>
using namespace std;
const int lim = 1e6;
int main() {
int a, b, c, d;
cin >> a >> b >> c >> d;
vector<long long> cnt(lim + 2);
for (int x = a; x <= b; ++x) {
++cnt[x + b];
--cnt[x + c + 1];
}
for (int i = 0; i <= lim; ++i) {
cnt[i + 1] += cnt[i];
}
auto res = 0LL;
for (int i = 0; i <= lim; ++i) {
res += cnt[i] * max(min(d, i - 1) - c + 1, 0);
}
cout << res << '\n';
}
#include <bits/stdc++.h>
using namespace std;
int main() {
long long A, B, C, D;
cin >> A >> B >> C >> D;
long long ans = 0;
for(long long z = C; z <= D; z++) {
long long now = 0;
if(z < 2*B && z < C+A) {
now = (B-A+1) * (C-B+1);
if(z >= A+B) now -= (z-A-B+1) * (z-A-B+2) / 2;
}
else if(z >= 2*B-1 && z >= A+C-1) {
now = (B+C-z) * (B+C-z+1) / 2;
if(z > B+C) break;
}
else {
long long l = B+C - z;
long long w = l - min(C-B+1, B-A+1);
now = l * (l+1) / 2- w * (w+1) / 2;
now = max(0LL, now);
}
ans += now;
}
cout << ans << endl;
return 0;
}
首先我們要先知道構成三角形需要的條件就是「最長邊
這次是告訴你,短邊與長邊一定差一倍,其實就是跟你說,不可能有兩短一長的方式能夠分組成功。
所以就只有三個同樣能力的可以分組成功,以及兩神帶一坑可以分組成功。
之後就是統計有幾個坑,讓神去帶,就可以分完了!
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n;
ll ans, s;
vector< ll > a;
int main() {
cin >> n;
a.resize(n);
for(int i = 0; i < n; i++) cin >> a[i];
for(int i = 0; i < n; i++) {
ll pls = 0;
if(s > 0) pls += (min(s, (a[i]/2))), s -= pls, a[i] -= (2*pls);
ans += (pls+(a[i]/3));
s += (a[i]%3);
}
cout << ans << endl;
return 0;
}
使用拓展歐幾里德法,尋找整數對
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
ll A, B, C, n;
bool sw = 0;
cin >> A >> B >> C;
vector<ll> R, x, y;
R.push_back(max(A, B));
R.push_back(min(A, B));
if(A < B) sw = 1;
for(int i = 1; R[i]; i++) R.push_back(R[i-1]%R[i]);
n = R.size();
x.resize(n);
y.resize(n);
x[0] = y[1] = 1;
for(int i = 2; i < n; i++) {
x[i] = x[i-2];
y[i] = y[i-2];
x[i] -= (R[i-2]/R[i-1])*x[i-1];
y[i] -= (R[i-2]/R[i-1])*y[i-1];
}
if(sw == 1) swap(x, y);
ll gcd_n = R[n-2];
if(C % gcd_n) {
cout << "N" << endl;
return 0;
}
ll X = x[n-2] * (C / gcd_n), Y = y[n-2] * (C / gcd_n);
if(x[n-1] < 0) x[n-1] = -x[n-1], y[n-1] = -y[n-1];
if(X >= (x[n-1]) || X < 0) {
X = (X%x[n-1] + x[n-1]) % x[n-1];
Y = (C-X*A) / B;
}
cout << "Y" << endl;
cout << X << " " << Y << endl;
return 0;
}
因為本題需求精度很高,推薦使用 python 內建大數作答,不過使用 c++ 還是可以通過的,python 的解答利用 pow(11,31) 來精確算出 pow(1.1,31) 的值,再利用 fake 算出假的值用以推算答案位數,並且由於
這裡提供第三筆測資,供各位參考測試
6
1970763
1981934
1977038
1674590
296173
1378417
t = int(input())
a = pow(11, 31)
fake_a = pow(1.1, 31)
for i in range(0, t):
b = int(input())
fake = int(fake_a * b / 2)
ans = a * b >> 1
ans_len = len(str(fake))
ans = int(str(ans)[:ans_len]) + 1
print(ans)
// 利用上課所教的方法進行作答
#include <bits/stdc++.h>
using namespace std;
int main() {
long long t, a, b, i, j, k;
long double ld;
cin >> t;
while (t--) {
cin >> b;
ld = pow(1.1, 31) * b / 2;
if (abs(ld - (long long)(ld)) <= ld * 1e-14) {
cout << (long long)(ld) << endl;
} else {
cout << (long long)(ld + 1) << endl;
}
}
return 0;
}
暴力枚舉每個工作要不要做,要做就要上前面的實習課,共
因為至多參加一堂實習課,因此只要工作報酬比實習課的花費還多,或是工作不需要上實習課,就可以做那份工作,只要將這些工作報酬加總減掉實習課花費就能有最大獲利。
因為實習課不重複,因此只要稍微擴展一下 Subtask 2 的算法即可。
其實這題最後是決定要做哪些工作,因為要上哪些實習課是由做哪些工作決定,以題目敘述來說,要做
這時我們就能使用最小割來解決這題,但是要經過一些轉化,先加上源點及匯點,以及將點權轉化為割的容量,如果我們要選擇一個點,則將其放在源點這端,否則放在匯點端,接著考慮頂點的選擇狀況:
題目經轉化會變成下圖
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
const int MAXN = 4005, INF = 1e9;
struct MaxFlow{
struct edge{
int to, cap, flow, rev;
};
vector<edge> v[MAXN];
int s, t, dis[MAXN], cur[MAXN];
int dfs(int u, int cap){
if(u == t || !cap)
return cap;
for(int &i = cur[u]; i < v[u].size(); i++){
edge &e = v[u][i];
if(dis[e.to] == dis[u] + 1 && e.flow != e.cap){
int df = dfs(e.to, min(e.cap - e.flow, cap));
if(df){
e.flow += df;
v[e.to][e.rev].flow -= df;
return df;
}
}
}
dis[u] = -1;
return 0;
}
bool bfs(){
memset(dis, -1, sizeof(dis));
queue<int> q;
q.push(s), dis[s] = 0;
while(!q.empty()){
int tmp = q.front();
q.pop();
for(auto u : v[tmp]){
if(!~dis[u.to] && u.flow != u.cap){
q.push(u.to);
dis[u.to] = dis[tmp] + 1;
}
}
}
return dis[t] != -1;
}
int maxflow(int _s, int _t){
s = _s, t = _t;
int flow = 0, df;
while(bfs()){
memset(cur, 0, sizeof(cur));
while(df = dfs(s, INT_MAX))
flow += df;
}
return flow;
}
void add_edge(int st, int ed, int cap){
v[st].push_back(edge{ed, cap, 0, v[ed].size()});
v[ed].push_back(edge{st, 0, 0, v[st].size() - 1});
}
} dinic;
int main() {
int n, m, s, b, k, x, sum = 0;
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> s;
sum += s;
dinic.add_edge(0, i, s);
}
for(int i = 1; i <= m; i++){
cin >> b;
dinic.add_edge(i + 2000, 4004, b);
}
for(int i = 1; i <= n; i++){
cin >> k;
while(k--){
cin >> x;
dinic.add_edge(i, x + 2000, INF);
}
}
cout << sum - dinic.maxflow(0, 4004) << "\n";
}