2020.7.19 排位赛(二)

2020/7/19 排位赛(二)

A Colliding Balls

solution

  1. 两个球碰撞的条件: xi * ui = yj * vj;
  2. 每个球在碰撞后会消失,一个球如果能和多个球碰撞,那么首先会和坐标值最小的碰撞。
  3. 用muiltiset。

code

/*******************
Problem:
Author:CXY1999
Status:Coding
Head Vision 2.1
*******************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

define pb push_back

define BG begin()

define ED end()

typedef long long LL;
using namespace std;
multiset s;

int main() {
ios::sync_with_stdio(0);
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++) {
LL l, r;
cin >> l >> r;
s.insert(l * r);
}
int Ans = 0;
for (int i = 0; i < m; i++) {
LL l, r;
cin >> l >> r;
if (s.count(l * r)) {
multiset::iterator t = s.find(l * r);
s.erase(t);
Ans++;
}
}
cout << Ans << endl;
}

B Awkwardness Minimization

solution

交叉着排,剩余的放两边。然而不会证明…
思路: 可以先猜出一个解,然后看交换任意两个结果会不会更优/差。
以后遇到这类问题可以打表,打表,打表!

code

include

include

include

include

include

include

include

using namespace std;
#define MP make_pair
#define fi first
#define se second
#define pb push_back
typedef long long ll;
typedef pair<int, int> pii;
int T;
string str;
long long he(ll tail,ll size)
{
long long ans=(1+tail)size/2;
return ans;
}
int main()
{
cin>>T;
while(T--)
{
cin>>str;
ll cntb=0,cntg=0;
for(ll i=0; i<str.size(); i++)
{
if(str[i]=='b')
cntb++;
else
cntg++;
}
long long ans=0;
ll dis=abs(cntb-cntg);
ll cnt=min(cntb,cntg);
for(ll i=1; i<=cnt; i++)
{
ans+=(i
2-1)((cnt-i+1)2-1);
// 数值 个数
}
// cout<<"temp:"<<ans<<endl;
if(cntb!=cntg)
{
ll g0=he(cnt2-1,cnt);
ans+=g0;
dis--;
ans+=g0
(dis/2)2+cnthe(dis/2,dis/2)2;
if(dis%2==1)
ans+=g0+cnt
(dis/2+1);
//
// // ans+= (1+cnt2-1)cnt/2dis+cnt( 1+(dis/2) )
// ans+= he(1+cnt2-1,cnt)dis+cnthe((dis-1)/2,(dis-1)/2)2;
// // 累加和 * 个数 + 多增加cnt个数
// // ans+= he(1+cnt2-1,cnt)dis+cnt(dis/2);
// if(dis%2==0)
// ans+=cnt+dis/2+1;
}
cout<<ans<<endl;
}
return 0;
}
/

7
gb
bgg
bbgg
bbbggg
bbbgb
bbbggggggggggg
bbbgggg

//
1
2
6
19
6
139 ? ggggg bgbb ggggg

*/

C Special Graph Construction

solution

  1. 设顶点数为 n,则边数 m = n*3/2;
  2. 把每个连通块看成一个顶点的话,图是一个有 k 条边,k+1 个顶点的树。
    • k>=1
      要想整个图是一个二分图,则去掉桥后,每个连通块是一个二分图。在树的叶子节点连通块内,有一个顶点的度数为2(因为去掉了桥边),其他顶点度数为3,显然不能构成二分图(二分图两边点集的度数和相等)。所以至少得去掉一个边,对于一个节点数大于1(即k>=1)的树来说,叶子节点至少为2,所以说至少得去掉两条边才能保证是二分图,即f(G)>=2.
    • k=0
      直接输出样例
  3. 构造
    构造图见官方题解

code

include <bits/stdc++.h>

using namespace std;

int main() {
int k;
scanf("%d", &k);
if (k == 0) {
printf("6 9\n1 4\n1 5\n1 6\n2 4\n2 5\n2 6\n3 4\n3 5\n3 6\n0\n");
return 0;
}
int n = 10 + (k - 1) * 6, m = n * 3 / 2;
printf("%d %d\n", n, m);
for (int i = 1; i < 5; ++i) {
printf("%d %d\n", i, i + 1);
}
printf("1 5\n");
printf("1 3\n2 4\n");

for (int i = 6; i < 10; ++i) {
printf("%d %d\n", i, i + 1);
}
printf("6 10\n");
printf("6 8\n7 9\n");

int now = 5, n1 = 11;
for (int i = 1; i < k; ++i) {
printf("%d %d\n", now, n1);
for (int j = n1; j < n1 + 5; ++j) {
printf("%d %d\n", j, j + 1);
}
for (int j = 0; j < 3; ++j) {
printf("%d %d\n", n1 + j, n1 + j + 3);
}
now = n1 + 5;
n1 = now + 1;
}
printf("%d %d\n", now, 10);
printf("2 2 9\n");
return 0;
}

D Minimum Variance

solution

要求: 方差的最小值 * n2 = n * (平方的和) - (和的平方).

  1. 正解
    直接枚举平均值,然后计算方差的最小值,直接计算会超时,要用到扫描线。
  2. 看不懂的解法
    先从最小平均值开始,不断迭代。其实原理和扫描线算法是一样的。

code

  1. 正解

    include <bits/stdc++.h>

    using namespace std;
    const int N = 50000 + 10;

    int n, sz[N];
    vector vec[N];
    vector< pair<int,int> > issues[N];
    typedef long long LL;

    LL sum = 0, sum2 = 0;
    void rep(LL x, LL y) {
    sum2 -= xx, sum -= x;
    sum2 += y
    y, sum += y;
    }

    LL getAns() {
    return sum2 * n - sum * sum;
    }
    LL ans = 1e18;
    LL tackle() {
    sum2 = 0, sum = 0;
    for (int i = 1; i <= n; i ++) {
    sum += vec[i][0];
    sum2 += 1LL * vec[i][0] * vec[i][0];
    // printf("# %lld\n", vec[i][0]);
    }
    // printf("ans = %lld\n", getAns());
    ans = min(ans, getAns());
    for (int i = 1; i <= 50000; i ++) {
    for (auto p: issues[i]) {
    rep(p.first, p.second);
    }
    ans = min(ans, getAns());
    }
    }

    int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++) {
    scanf("%d", &sz[i]);
    for (int j = 0; j < sz[i]; j ++) {
    int x; scanf("%d", &x);
    vec[i].push_back(x);
    }
    sort(vec[i].begin(), vec[i].end());
    }
    // RIG
    for (int i = 1; i <= n; i ++) {
    for (int j = 0; j + 1 < vec[i].size(); j ++) {
    int l = vec[i][j], r = vec[i][j+1];
    if ((r - l) % 2 == 0) {
    issues[(l+r)/2].push_back(make_pair(vec[i][j], vec[i][j+1]));
    } else {
    issues[(l+r+1)/2].push_back(make_pair(vec[i][j], vec[i][j+1]));
    }
    }
    }
    tackle();
    // LEF
    for (int i = 1; i <= 50000; i ++) issues[i].clear();
    for (int i = 1; i <= n; i ++) {
    for (int j = 0; j + 1 < vec[i].size(); j ++) {
    int l = vec[i][j], r = vec[i][j+1];
    if ((r - l) % 2 == 0) {
    issues[(l+r)/2+1].push_back(make_pair(vec[i][j], vec[i][j+1]));
    } else {
    issues[(l+r+1)/2].push_back(make_pair(vec[i][j], vec[i][j+1]));
    }
    }
    }
    tackle();
    cout << ans << endl;
    }

  2. 其他

    include<bits/stdc++.h>

    using namespace std;
    typedef pair<int, int> pii;
    typedef long long ll;
    #define fi first
    #define se second
    #define all(x) (x).begin(),(x).end()
    const int N = 5e4 + 10;
    vector T[N];

    int main() {
    #ifdef local
    freopen("in.txt", "r", stdin);
    #endif
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int n; cin >> n;
    vector v;
    ll d2 = 0, d = 0;
    for(int i = 0; i < n; i++) {
    int sz; cin >> sz;
    v.resize(sz);
    for(auto &e : v) cin >> e;
    sort(all(v));
    for(int i = 0; i + 1 < sz; i++) {
    int t = (v[i] + v[i + 1] + 1) / 2;
    T[t].emplace_back(v[i], v[i + 1]);
    }
    d2 += (ll) v[0] * v[0];
    d += v[0];
    }
    ll ans = n * d2 - d * d;
    for(int i = 0; i < N; i++) {
    if(T[i].empty()) continue;
    for(auto &e : T[i]) {
    d -= e.fi;
    d2 -= (ll) e.fi * e.fi;
    d += e.se;
    d2 += (ll) e.se * e.se;
    }
    ans = min(ans, n * d2 - d * d);
    }
    cout << ans << '\n';
    return 0;
    }

E Colorful Balloons (搁置)

要用到fft。

F Recover Array

solution

分成三个一组,先查询这一组的和 sum;

  1. sum = 3 或 sum = 0 则这一组的值就全知道了(查询次数为1);
  2. sum = 1, 随机查询三个位置中的一个,设值为 x ;
    • x = 1, 则其余两个值为0(查询次数为2);
    • x = 0, 则还得再查询一次(查询次数为3);
  3. sum = 2, 与 sum = 1 同理。

可以证明这样能在9e4次查询内求出结果的概率非常大(我不会证qwq)。

code

include <bits/stdc++.h>

using namespace std;
int n = 1e5;
int a[100010];

int ask(int l, int r) {
int res;
printf("1 %d %d\n", l, r);
fflush(stdout);
scanf("%d", &res);
return res;
}

int main() {
srand(time(0));
for (int i = 1; i + 2 <= n; i += 3) {
int sum = ask(i, i + 2);
if (sum == 3) {
a[i] = a[i + 1] = a[i + 2] = 1;
} else if (sum == 0) {
a[i] = a[i + 1] = a[i + 2] = 0;
} else {
int r = rand() % 3;
int r2 = (r + 1) % 3, r3 = (r + 2) % 3;
a[i + r] = ask(i + r, i + r);
if (a[i + r] && sum == 1) {
a[i + r2] = a[i + r3] = 0;
} else if (!a[i + r] && sum == 2) {
a[i + r2] = a[i + r3] = 1;
} else {
a[i + r2] = ask(i + r2, i + r2);
a[i + r3] = sum - a[i + r2] - a[i + r];
}
}
}
a[n] = ask(n, n);
printf("2");
for (int i = 1; i <= n; ++i) {
printf(" %d", a[i]);
}
fflush(stdout);
}

G Train or Walk

solution

签到题

code

include <bits/stdc++.h>

using namespace std;
int ps[20010];
int main() {
int T; scanf("%d", &T);
while(T--) {
int n,a,b,c,d,p,q,y;
scanf("%d%d%d%d%d%d%d%d", &n,&a,&b,&c,&d,&p,&q,&y);
for(int i = 1; i<=n; ++i)
scanf("%d", &ps[i]);
int ans = abs(ps[b]-ps[a])p;
int tmp = abs(ps[c]-ps[a])
p;
if(tmp>y) {
tmp = 2e9;
}else {
tmp = y;
tmp+=abs(ps[d]-ps[c])q;
tmp+=abs(ps[b]-ps[d])
p;
}
printf("%d\n",min(ans,tmp));
}
return 0;

}

H Substring Matching (搁置)

本场比赛最难的题,不会。好像是动态规化+单调队列。

I Direct Segments (搁置)

好像是2-sat的板子

K Chef and Diamonds

一个非常不错的期望题,我一开始只想出来了一个O(n)的算法,超时,我想着优化,结果是一开始的思路就错了。

solution

n个巧克力,q个钻石。
考虑一个巧克力的位置,可能在第0个钻石后面第1个钻石前面,1个钻石后面第2个钻石前面…q个钻石后面,巧克力在q个钻石后面的概率为1/(q+1),则总共n个钻石,在q个钻石后面的巧克力个数的期望是 n * (1/(q+1).
则去除q个钻石所需次数的期望是 n+q - n * (1/(q+1)).

code

include <bits/stdc++.h>

using namespace std;
typedef double db;
typedef long long ll;
int T;
int main() {
scanf("%d", &T);
while(T--){
db n,q;
scanf("%lf%lf", &n,&q);
printf("%.9lf\n",n+q-(q/(n+1)));
}
}

L Analytics Load Jobs

solution

一个题意比较复杂的二分答案,读懂题意就能做了。

code

include <bits/stdc++.h>

using namespace std;
const int N = 100010;
int n,K,J;
int id[N],c[N][3];
bool pd(int lim) {
int cntJ = 0, cntK;
for(int i = 1; i <= id[0]; ++i) {
++cntJ; cntK = 0;
int t1 = c[i][1],t2= c[i][2];
if(t2&&lim<2) return 0;
if(t1&&lim<1) return 0;
while(t1||t2){
++cntK;
int t = lim;
while(t>=2&&t2) {
t-=2; --t2;
}
while(t&&t1) {
--t; --t1;
}
}
if(cntK > K) {
cntJ+=ceil((double)(cntK-K)/K);
}
}
return cntJ<=J;
}
int main() {
int T; scanf("%d", &T);
while(T--) {
memset(id, 0, sizeof(id));
memset(c,0,sizeof(c));
scanf("%d%d%d", &n,&K,&J);
for(int i = 1; i<=n; ++i) {
int x,y; scanf("%d%d", &x,&y);
if(!id[x]) id[x] = ++id[0];
++c[id[x]][y];
}
int l = 1,r = 2*n,mid,ans;
while(l<=r) {
mid = (l+r)/2;
if(pd(mid)){
ans = mid; r = mid-1;
}else l = mid+1;
}
printf("%d\n",ans);
}
}

posted @ 2020-07-28 16:51  沐灵_hh  阅读(161)  评论(0)    收藏  举报