A - Three-Point Shot
題目大意
兩個球隊現在分數分別給出,問少的一方投入三分球之后是否能翻盤.
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
int main()
{
int a,b;cin >> a >> b;
if(a > b) swap(a,b);
if(a + 3 > b) cout << "Yes";
else cout << "No";
return 0;
}
B - Orthogonality
題目大意
給定兩個向量,問兩者內積是否是0.
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
const int N = 1e5+7;
int a[N],b[N];
int main()
{
ll res = 0;
int n,x,y;scanf("%d",&n);
forn(i,1,n) scanf("%d",&a[i]);
forn(i,1,n) scanf("%d",&b[i]);
forn(i,1,n) res += a[i] * b[i];
if(res == 0) puts("Yes");
else puts("No");
return 0;
}
C - ABC Tournament
題目大意
\(2^n\)個隊伍打比賽,每個隊伍有自己的分值,分值高的獲勝.對局呈完美二叉樹形態,從低到高,問第二名是誰.
思路
把整個局面划分兩段再遞歸,當區間里只有一個人的時候返回自己,其他時候返回兩個人對戰勝利者.記錄最后一個對局中輸掉的人的編號,即為第二名.
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
const int N = (1 << 16) + 7;
int a[N],last;
int solve(int l,int r)
{
if(l == r) return l;
int mid = l + r >> 1;
int lf = solve(l,mid),rt = solve(mid + 1,r);
if(a[lf] > a[rt]) return last = rt,lf;
else return last = lf,rt;
}
int main()
{
int n;scanf("%d",&n);
int m = 1 << n;
forn(i,1,m) scanf("%d",&a[i]);
solve(1,m);
printf("%d",last);
return 0;
}
D - Snuke Prime
題目大意:
有個公司售賣他們的\(n\)種服務,售賣方式有兩種:每天花費\(C\)元訂閱費,在訂閱期間任何服務可以直接使用;對\(i\)種服務花費\(c_i\)元每天使用.現給出若干個\(a_i,b_i,c_i\)表示在第\(a_i\)天到第\(b_i\)天需要使用第\(i\)種服務,以及使用這項服務的每天花費\(c_i\)
數據范圍:
\(1 \leq n \leq 2 * 10^5\)
\(1 \leq C \leq 10^9\)
\(1 \leq a_i \leq b_i \leq 10^9\)
\(1 \leq c_i \leq 10^9\)
思路
由於數據范圍過大,但是種類數只有\(2*10^5\)考慮離散化打標記.但是離散化只保留相對大小關系,使得"天數"這一信息被刪掉,因此離散化處理不了.
考慮掃描線,以天數為掃描線的划分.將所有服務分成兩個事件:一個事件包含兩個變量\({a,c}\)表示在第\(a\)天,增加一個每天花費為\(c\)的服務.對於原來的每種服務拆成\(\{a_i,c_i\}\)以及\(\{b_i+1,c_i\}\)兩個事件,表示第\(a_i\)天開始增加,直到\(b_i+1\)天結束.維護當前天數\(cur\)以及當前需要使用的各種服務的總花費\(sum\),因為可以通過訂閱的方式使用所有服務,所以每段的實際貢獻是\((a - cur) * min(sum,C)\).
將所有事件按左端點排序,掃描即可.
注意防范爆數據
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
typedef pair<ll,ll> pll;
#define x first
#define y second
#define int ll
const int N = 2e5+7;
struct Node
{
int a,b,c;
}a[N];
signed main()
{
int n,C;scanf("%lld%lld",&n,&C);
vector<pll> event;
forn(i,1,n) scanf("%lld%lld%lld",&a[i].a,&a[i].b,&a[i].c);
forn(i,1,n) event.push_back({a[i].a,a[i].c}),event.push_back({a[i].b + 1,-a[i].c});
sort(event.begin(),event.end());
int cur = 0;ll res = 0,sum = 0;
for(auto& _ : event)
{
int a = _.x,c = _.y;
res += 1ll*(a - cur) * min(max(sum,0ll),1ll*C);
sum += c;
cur = a;
}
printf("%lld",res);
return 0;
}
E - Peddler
題目大意
\(n\)點\(m\)邊有向圖,保證對於任何一條有向邊\((u,v)\)都有\(u < v\),即只會從編號較小的點連向較大的點.每個點都有一個值\(A_i\)表示在這個點買入黃金的價格和賣出黃金的價格.你不能在同一個點買入並賣出,求最大的獲利是多少.
你不能不買入,即使有負利潤也必須買.
圖可能不連通
思路
很惱火的一個題.
首先這個題有一個一般的解法,可以使用取極值的方式替代單源最短路的更新,這里不展開.
因為對於任何邊都有\(u < v\)所以這個圖是個DAG.直接\(dp\)即可.
-
狀態:\(f_u\)表示從起點走到\(u\)時,找到的最小的價格是多少.
-
入口:\(f_u = a_u\)
-
轉移:對於\(u\)的任何一條出邊對應的點\(v\),\(f_v = min(f_u,f_v)\)
更新答案\(res = max(res,a_u - f_u)\)
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
const int N = 2e5+7,M = N;
int edge[M],succ[M],ver[N],idx;
int w[N],deg[N];
ll f[N];
void add(int u,int v)
{
edge[idx] = v;
succ[idx] = ver[u];
ver[u] = idx++;
}
int main()
{
memset(ver,-1,sizeof ver);
int n,m;scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i) scanf("%d",&w[i]);
for(int i = 1;i <= m;++i)
{
int u,v;scanf("%d%d",&u,&v);
add(u,v);++deg[v];
}
queue<int> q;forn(i,1,n) if(!deg[i]) q.push(i);
forn(i,1,n) f[i] = 1e18;
ll res = -1e18;
while(!q.empty())
{
int u = q.front();q.pop();
res = max(res,w[u] - f[u]);
f[u] = min(f[u],1ll*w[u]);
for(int i = ver[u];~i;i = succ[i])
{
int v = edge[i];
f[v] = min(f[v],f[u]);
if(--deg[v] == 0) q.push(v);
}
}
printf("%lld",res);
return 0;
}
F - +1-1x2
題目大意
給你一個數\(x\),每次可以加一減一或乘二,問使\(x\)變成\(y\)的最小步數.
數據范圍:
\(1 \leq x,y \leq 10^{18}\)
思路
弱智題,顯然.
不過注意分情況討論奇數的時候,既有減一的拉回來的也有加一補上去的情況.
復雜度不知道,直覺是\(log\)的,可以沖的原因是直接的距離可以計算,其次乘2除2的速度非常快.
代碼
ll x,y;
map<ll,ll> f;
ll solve(ll y)
{
if(f.count(y)) return f[y];
ll res = y - x;
if(y <= x) return x - y;
if(y % 2 == 0) res = min(res,solve(y / 2) + 1);
else res = min({res,solve(y / 2) + 2,solve((y / 2 + 1)) + 2});
return f[y] = res;
}
int main()
{
cin >> x >> y;
cout << solve(y);
return 0;
}