本場鏈接:Codeforces Round #737 (Div. 2)
閑話
做的時候把C的條件轉錯了白做一個多小時.最后E由於假了所以就不寫了,有興趣自己補吧.
A. Ezzat and Two Subsequences
考慮平均值:最大值所在的組,會因為放入別的數而變小.每個數都需要在一個組,不難想到使最大值單獨成一個組即可.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
const int N = 1e5+7;
ll a[N];
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n;scanf("%d",&n);
forn(i,1,n) scanf("%lld",&a[i]);
sort(a + 1,a + n + 1);
ll sum = 0;forn(i,1,n - 1) sum += a[i];
printf("%.18lf\n",a[n] + 1.0 * sum / (n - 1));
}
return 0;
}
B. Moamen and k-subarrays
一段數可以在一起不動,當且僅當他們是連續增大的.為了方便不妨先把所有數映射成他們的rank,如此條件就等價於一段連續增大的段.求出段數\(cnt\)當\(cnt \leq k\)時可以划分.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
const int N = 1e5+7;
int a[N],d[N];
bool cmp(int x,int y)
{
return a[x] < a[y];
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n,k;scanf("%d%d",&n,&k);
forn(i,1,n) scanf("%d",&a[i]),d[i] = i;
sort(d + 1,d + n + 1,cmp);
forn(i,1,n) a[i] = d[i];
int cnt = 0;
forn(i,1,n)
{
int j = i;
while(j + 1 <= n && a[j + 1] == a[j] + 1) ++j;
++cnt;
i = j;
}
if(cnt <= k) puts("yes");
else puts("no");
}
return 0;
}
C. Moamen and XOR
原條件可以看做是有兩種情況:要么相同要么嚴格大於.如果嚴格大於說明存在某一位\(k\)在此位上左部嚴格大於右部,這樣只能是1/0
的情形,同時前半部分完全相同,后半部分隨意填充.
前半部分完全相同,分奇偶考慮組合數,后半部分隨意填顯然是\(2\)的長度冪次.如此,枚舉一個前綴相同,直到某一位產生嚴格大即可.(其實還能注意到\(n\)為奇數的時候可以直接有一個答案公式).
在實現的時候寫\(0\)下標會好寫一些.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
const int MOD = 1e9+7;
ll qpow(ll a,ll b,ll MOD)
{
ll res = 1;
while(b)
{
if(b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n,k;scanf("%d%d",&n,&k);
if(k == 0)
{
puts("1");
continue;
}
if(n == 1)
{
printf("%lld\n",qpow(2,k,MOD));
continue;
}
if(n % 2 == 1)
{
ll res = qpow(2,n - 1,MOD) + 1;
res = qpow(res,k,MOD);
printf("%lld\n",res);
}
else
{
ll res = qpow(2,k - 1,MOD);
res = qpow(res,n,MOD);
ll _ = qpow(2,n - 1,MOD);
_ = ((_ - 1) % MOD + MOD) % MOD;
_ = qpow(_,k,MOD);
res = (res + _) % MOD;
forn(j,1,k - 1)
{
ll nxt = ((qpow(2,n - 1,MOD) - 1) % MOD + MOD) % MOD;
nxt = qpow(nxt,j,MOD);
ll oth = qpow(2,n,MOD);
oth = qpow(oth,k - j - 1,MOD);
nxt = nxt * oth % MOD;
res = (res + nxt) % MOD;
}
printf("%lld\n",res);
}
}
return 0;
}
D. Ezzat and Grid
數據范圍很吊比,先不看那么多,考慮直接做:每一行有刪和不刪兩種決策,而且由於刪這個操作不好表達信息,考慮計算保留行數:
- 狀態:\(f[i]\)表示前\([1,i]\)行中最多可以保留的行數.但是有個問題,這樣沒有前面狀態在哪一行有\(1\)可以貼上去的信息,如此:\(f[i][j]\)表示前\([1,i]\)行中,強制保留第\(i\)行且第\(i\)行第\(j\)列有\(1\)的最多保留數.
- 入口:全部置\(0\)即可.
- 轉移:考慮第\(i\)行保留下來的轉移方式:若第\(k\)行的第\(j\)列與\(i\)行的第\(j\)列同時存在,則可以從\(f[k][j]\)轉移到\(f[i][j]\).
- 出口:枚舉最大值即可.
這樣直接做顯然復雜度會達到\(O(n^2)\).可以發現\(j\)維的轉移事實上等價於在區間上加和以及求區間上的最值.所以可以開一個線段樹維護\(j\)維,將每一層一段\(1\)看做是一個區間求最值的操作(由前面的行轉移而來),每層做完之后對本行做覆蓋.
但是本題還需要求方案,常規來說,只需記錄\(f[i]\)的轉移前驅是誰即可,即維護一個\(succ[i]\)表示\(f[i]\)是由那個狀態轉移來的.在線段樹上維護最值得同時維護最值來源的下標即可找到上一個保留的行具體是誰,如此即可找出在最優方案中具體保留了哪些行.即可將答案輸出.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
#define l first
#define r second
const int N = 1e6+7,INF = 1e9;
const pii PZ = {0,-1};
vector<int> vals;
vector<pii> E[N];
int PID[N],st[N];
struct Node
{
int l,r;
pii v,lazy;
}tr[N * 4];
inline int link(int x)
{
return lower_bound(vals.begin(),vals.end(),x) - vals.begin() + 1;
}
void pushup(int u)
{
tr[u].v = max(tr[u << 1].v,tr[u << 1 | 1].v);
}
void pushdown(int u)
{
auto& lf = tr[u << 1],&s = tr[u],&rt = tr[u << 1 | 1];
if(s.lazy == PZ) return ;
s.v = max(s.v,s.lazy);
lf.lazy = max(lf.lazy,s.lazy);lf.v = max(lf.v,lf.lazy);
rt.lazy = max(rt.lazy,s.lazy);rt.v = max(rt.v,rt.lazy);
s.lazy = PZ;
}
void build(int u,int l,int r)
{
if(l == r) tr[u] = {l,r,PZ,PZ};
else
{
int mid = l + r >> 1;
tr[u] = {l,r};
build(u << 1,l,mid),build(u << 1 | 1,mid + 1,r);
pushup(u);
}
}
void modify(int u,int l,int r,pii& v)
{
if(tr[u].l >= l && tr[u].r <= r)
{
tr[u].v = max(tr[u].v,v);
tr[u].lazy = max(tr[u].lazy,v);
return ;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) modify(u << 1,l,r,v);
if(r > mid) modify(u << 1 | 1,l,r,v);
pushup(u);
}
pii query(int u,int l,int r)
{
if(tr[u].l >= l && tr[u].r <= r) return tr[u].v;
int mid = tr[u].l + tr[u].r >> 1;pii res = PZ;
pushdown(u);
if(l <= mid) res = max(res,query(u << 1,l,r));
if(r > mid) res = max(res,query(u << 1 | 1,l,r));
return res;
}
int main()
{
memset(PID,-1,sizeof PID);
int n,m;scanf("%d%d",&n,&m);
forn(i,1,m)
{
int p,l,r;scanf("%d%d%d",&p,&l,&r);
vals.push_back(l);vals.push_back(r);
E[p].push_back({l,r});
}
sort(vals.begin(),vals.end());
vals.erase(unique(vals.begin(),vals.end()),vals.end());
forn(i,1,n) for(auto& _ : E[i]) _.l = link(_.l),_.r = link(_.r);
build(1,1,N - 1);
forn(i,1,n)
{
if(E[i].empty()) continue;
pii mx = PZ;
for(auto& _ : E[i]) mx = max(mx,query(1,_.l,_.r));
// modify(1,1,N - 1,mx);
PID[i] = mx.r;
++mx.l;
mx.r = i;
for(auto& _ : E[i]) modify(1,_.l,_.r,mx);
}
pii res = query(1,1,N - 1);
int cur = res.r;
while(cur != -1)
{
st[cur] = 1;
cur = PID[cur];
}
printf("%d\n",n - res.l);
forn(i,1,n) if(!st[i]) printf("%d ",i);
puts("");
return 0;
}