Educational Codeforces Round 171 (Rated for Div. 2)题解记录
比赛链接:https://codeforces.com/contest/2026
A. Perpendicular Segments
题目说了必定有答案,不妨想一想对于\(x,y\)来讲,最大值肯定是相应数构成得正方形得对角线最大,其一定大于等于\(k\),既然最小的正方形满足
直接都取最小的正方形即可(对角线垂直),所以取\(min(x,y)\)
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
using namespace std;
mt19937 rnd(time(0));
const ll mod=1e9+7;
const ll N=2e5+5;
ll ksm(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1)
ans=(ans%mod*x%mod)%mod;
x=x%mod*(x%mod)%mod;
y>>=1;
}
return ans%mod%mod;
}
ll gcd(ll x,ll y)
{
if(y==0)
return x;
else
return gcd(y,x%y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
ll x,y,k;
cin>>x>>y>>k;
ll j=min(x,y);
cout<<0<<" "<<0<<" "<<j<<" "<<j<<endl;
cout<<j<<" "<<0<<" "<<0<<" "<<j<<endl;
}
}
B. Black Cells
二分版:
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
using namespace std;
mt19937 rnd(time(0));
const ll mod=1e9+7;
const ll N=2e5+5;
ll ksm(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1)
ans=(ans%mod*x%mod)%mod;
x=x%mod*(x%mod)%mod;
y>>=1;
}
return ans%mod%mod;
}
ll gcd(ll x,ll y)
{
if(y==0)
return x;
else
return gcd(y,x%y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll a[250000];
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
ll n;
cin>>n;
if(n==1)
{
ll b;
cin>>b;
cout<<1<<endl;
continue;
}
for(ll i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n);
//a[n+1]=0;
if(n%2==0)
{
ll ans=0;
for(ll i=1;i<=n-1;i+=2)
{
ans=max(ans,a[i+1]-a[i]);
}
cout<<ans<<endl;
}
else
{
ll l=1,r=1e18;
while(l<r)
{
ll mid=(l+r)>>1;
ll gs=1;
ll cnt=0;
ll pd=0;
while(gs<=n-1)
{
if(a[gs+1]-a[gs]<=mid)
{
gs+=2;
continue;
}
else
{
if(cnt==1){
pd=1;
break;
}
gs++;
cnt++;
continue;
}
}
if(pd)
l=mid+1;
else
r=mid;
}
cout<<r<<endl;
}
}
}
枚举版:
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
using namespace std;
mt19937 rnd(time(0));
const ll mod=1e9+7;
const ll N=2e5+5;
ll ksm(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1)
ans=(ans%mod*x%mod)%mod;
x=x%mod*(x%mod)%mod;
y>>=1;
}
return ans%mod%mod;
}
ll gcd(ll x,ll y)
{
if(y==0)
return x;
else
return gcd(y,x%y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll a[325000];
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
ll n;
cin>>n;
for(ll i=1;i<=n;i++)cin>>a[i];
a[n+1]=0;
a[n+2]=0;
ll ans=0;
if(n%2==0)
{
for(ll i=1;i<=n;i+=2)
{
ans=max(ans,a[i+1]-a[i]);
}
}
else
{
ans=1e18;
for(ll i=1;i<=n;i+=2)
{
ll cnt=0;
for(ll j=1;j<=n;j+=2)
{
if(i==j)cnt=max(cnt,1ll),j++;
cnt=max(cnt,a[j+1]-a[j]);
}
ans=min(ans,cnt);
}
}
cout<<ans<<endl;
}
}
C. Action Figures
分析可得0点必选买,非0点优先用0点消除,否则用下标最小的1点消除
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
using namespace std;
mt19937 rnd(time(0));
const ll mod=1e9+7;
const ll N=2e5+5;
ll ksm(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1)
ans=(ans%mod*x%mod)%mod;
x=x%mod*(x%mod)%mod;
y>>=1;
}
return ans%mod%mod;
}
ll gcd(ll x,ll y)
{
if(y==0)
return x;
else
return gcd(y,x%y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll a[550000];
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
ll mo=1;
ll n;
cin>>n;
string f;
cin>>f;
set<ll>q,k;
ll op=0;
ll ans=0;
for(ll i=1;i<=n;i++)
{
if(f[i-1]=='0')
q.insert(i);
else
k.insert(i);
}
for(ll i=f.size()-1;i>=0;i--)
{
if(f[i]=='1')
{
ll c=(i+1);
auto j=k.lower_bound(c);
if(j!=k.end())
{
if(q.size()>0)
{
ll u=*q.rbegin();
q.erase(u);
ans+=u;
k.erase(c);
}
else
{
if(k.size()==1)
{
ans+=c;
k.clear();
}
else
{
ll u=*k.begin();
k.erase(c);
k.erase(u);
ans+=u;
}
}
}
}
else
{
ll u=i+1;
if(q.lower_bound(u)!=q.end())
{
q.erase(u);
ans+=u;
}
}
//cout<<ans<<endl;
}
cout<<ans<<endl;
}
}
D. Sums of Segments
优化暴力
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
using namespace std;
mt19937 rnd(time(0));
const ll mod=1e9+7;
const ll N=2e5+5;
ll ksm(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1)
ans=(ans%mod*x%mod)%mod;
x=x%mod*(x%mod)%mod;
y>>=1;
}
return ans%mod%mod;
}
ll gcd(ll x,ll y)
{
if(y==0)
return x;
else
return gcd(y,x%y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll a[325000];
ll pre[325000];//一维前缀
ll pre1[325000];//类似二维
ll sub[320555];
ll pre3[325000];
//1
//1 2
//1 2 5
//1 2 5 10
ll n;
set<pair<ll,ll>>q;
ll qu(ll x)
{
ll ans=0;
auto j=q.lower_bound({x,0});
ll zq=(*j).second;
ans+=pre3[zq-1];
j--;
ll wz=x-(*j).first+zq-1;
ans+=pre1[zq]-sub[wz+1]-(pre[wz]-pre[zq-1])*(n-zq-(wz-zq));
return ans;
}
int main()
{
fio();
ll t;
t=1;
while(t--)
{
q.clear();
cin>>n;
ll cnt=0;
for(ll i=1;i<=n;i++)cin>>a[i],pre[i]=pre[i-1]+a[i],cnt+=pre[i];
pre1[1]=cnt;
for(ll i=2;i<=n;i++)pre1[i]=pre1[i-1]-(n-i+2)*a[i-1];
for(ll i=1;i<=n;i++)pre3[i]=pre3[i-1]+pre1[i];
sub[n+1]=0;
for(ll i=n;i>=1;i--)sub[i]=sub[i+1]+a[i]*(n-i+1);
q.insert({0,0});
cnt=0;
for(ll i=1;i<=n;i++)
{
cnt+=(n-i+1);
q.insert({cnt,i});
}
ll op;
cin>>op;
while(op--)
{
ll l,r;
cin>>l>>r;
cout<<qu(r)-(l-1?qu(l-1):0)<<endl;
}
}
}
E. Best Subsequence
题目的意思其实等价于(选的数的个数-选的数中所有二进制存在等于1的不同位置数)
一开始补题,没思路,后面去参考别人题解了。浅学了点网络流最大流,回来一看,确实这个挺板子的
先构建大于0的数和其二进制位置(大于1)的边,然后再构建一个超级源点和大于0的数连边(阈值为1),超级汇点和所有二进制位数的连边(阈值为1)
随后走一遍最大流,然后n-这个最大流即使答案,注意m(浅算一下,最多\(2*(60*100+100+60)\)个边)要开双倍
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
using namespace std;
const ll N = 170, M = 16000, INF = 0x3f3f3f3f, mod = 1e9 + 7;
ll n, m, s, t, dis[N], cur[M];//当前弧优化
ll e[M], ne[M], w[M], h[M], idx;
void add(ll l, ll r, ll v)
{
e[idx] = r;
w[idx] = v;
ne[idx] = h[l];
h[l] = idx++;
}
bool bfs()//分层
{
queue<ll>q;
memset(dis, -1, sizeof(dis));
q.push(s);
dis[s] = 0;
cur[s] = h[s];
while (!q.empty())
{
ll u = q.front();
q.pop();
for (ll i = h[u]; ~i; i = ne[i])
{
ll v = e[i];
if (dis[v] == -1 && w[i])
{
dis[v] = dis[u] + 1;
cur[v] = h[v];
if (v == t)
return 1;
q.push(v);
}
}
}
return 0;
}
ll dfs(ll u, ll limit)
{
if (u == t)
return limit;
ll flow = 0;
for (ll i = cur[u]; ~i; i = ne[i])
{
cur[u] = i;
ll v = e[i];
if (dis[v] == dis[u] + 1 && w[i])
{
ll minf = dfs(v, min(w[i], limit - flow));
w[i] -= minf;
w[i ^ 1] += minf;
flow += minf;
if (flow == limit)
return flow;
}
}
return flow;
}
ll dinic()
{
ll ans = 0;
while (bfs())
{
ans += dfs(s, INF);
}
return ans;
}
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
ans = (ans % mod * x % mod) % mod;
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll a[250];
int main()
{
fio();
ll k;
cin >> k;
while (k--)
{
idx = 0;
memset(h, -1, sizeof h);
cin >> n;
ll cnt = 0;
ll ans = 0;
for (ll i = 1; i <= n; i++)
{
ll x;
cin >> x;
if (x)cnt++,a[cnt] = x;
}
s = n + 63, t = n + 64;
for (ll i = 1; i <= cnt; i++)
{
add(s, i, 1);
add(i, s, 0);
}
for (ll i = 0; i <= 60; i++)
{
add(n + i+1, t, 1);
add(t, n + i+1, 0);
}
for (ll i = 1; i <= cnt; i++)
{
for (ll j = 0; j <= 60; j++)
{
if (a[i] & (1ll << j))
{
add(i, n + j+1, 1);
add(n + j+1, i, 0);
}
}
}
cout << n - dinic() << endl;
}
}