2020牛客多校第二场训练补题记录

2020牛客多校第二场

场上解决:C,D,F

已补题: A,B,G,H,J,K

All with Pairs

字符串

题意

给你n个字符串,定义 f ( s , t ) f(s,t) f(s,t)表示串s的前缀和t的后缀的最长匹配长度求:
∑ i = 1 n ∑ j = 1 n f ( s i , s j ) 2 ( m o d   998244353 ) \sum_{i=1}^{n}\sum_{j=1}^{n}f(s_i,s_j)^2(mod\ 998244353) i=1nj=1nf(si,sj)2(mod 998244353)

解法

hash字符串的后缀,利用map计数,枚举每个字符串的前缀,找到多少个与之匹配的后缀,但对于同一个字符串,倘若前缀a,为前缀b的后缀,应该只计算前缀b,这显然就是 k m p kmp kmp的next数组。枚举时对每个字符串从前往后枚举
c n t [ i ] = m a p [ h a s h ( p r e ( i ) ) ] , c n t [ n e x t [ i ] ] − = c n t [ i ] cnt[i] = map[hash(pre(i))],cnt[next[i]]-=cnt[i] cnt[i]=map[hash(pre(i))],cnt[next[i]]=cnt[i]

#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
#define pi 3.1415926535
using namespace std;
const int mod = 998244353;
ll d[1000005];
string s[100005];
char p[1000005];
int n;
map num;
int Next[1000005];
ll cnt[1000005];
int b;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    d[0] = 1;
    b = 113;
    for(int i=1;i<1000002;i++){
        d[i] = d[i-1]*b;
    }
    cin>>n;
    for(int i=0;i>s[i];
        int len = s[i].length();
        ll val = 0;
        for(int j = len-1;j>=0;j--){
            val+=d[len-j-1]*(s[i][j]-'a'+1);
            num[val]++;
        }
    }
    ll ans = 0;
    for(int k=0;k 0 && p[i] != p[j+1]) j=Next[j];
            if(p[i] == p[j+1]) j++;
            Next[i]=j;
            val*=b;
            val+=p[i]-'a'+1;
            cnt[i] = num[val];
            if(j) cnt[j] -= cnt[i];
        }
        for(ll j=1;j<=m;j++){
            ans+=1ll*cnt[j]%mod*(j)%mod*(j)%mod;
            ans %= mod;
        }
    }
    cout<

Boundary

计算几何

题意

给你n个点,保证不重复且不在原点,求在所有经过原点的圆中,圆上给定点最多的数目是多少

解法

将每个点与原点相连,得到这条线段的垂直平分线,共有n条,n条垂直平分线两两相交得到可能的圆心,统计一个圆心出现的次数,次数最多的圆心所在圆即答案所在圆,计算这个圆心所在圆上的给定点数目(注意判断共线问题和一个点的情况);

#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pll pair
#define pi 3.1415926535
using namespace std;
const double eps = 1e-6;
int n,tot;
struct nodi{
    int x,y;
}a[2005];
struct nodd{
    double x,y;
}b[5000005];
bool cmp(nodd a,nodd b){
    if(fabs(a.x - b.x)

Cover the Tree

贪心,树

题意

给你一颗树,用最少的链覆盖所有的边

解法

答案显然是将叶子两两相连,数目是 ⌈ 叶 子 数 目 / 2 ⌉ \lceil叶子数目/2\rceil /2,考虑如何构造解,
在这里插入图片描述

或者可以考虑随机算法,随机若干次直到满足。

Duration

签到题,模拟

题意

给你一天的两个时刻,求相差的秒数

解法

全部化成秒,相减取绝对值

Exclusive OR

FWT

题意

给你n个整数, A 1 , A 2 , . . . , A n A_1,A_2,...,A_n A1,A2,...,An,输出i个数,第i个数为从给你的数中选出i个数的异或值的最大值,可以重复选择

解法

小范围暴力,大范围规律,对于 i > 19 i>19 i>19之后有 a n s i = a n s i − 2 ans_i =ans_{i-2} ansi=ansi2,因为A< 2 18 2^{18} 218,所以最多第19轮达到满秩,小范围暴力可以依靠异或卷积FWT完成

#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
using namespace std;
const int N = (1<<18);
const int MOD = 998244353;
ll qpow(ll a,ll b){
    ll res = 1;
    while(b){
        if(b&1) res = res * a % MOD;
        b>>=1;
        a = a*a%MOD;
    }
    return res;
}
int inv2 ;
void FWT_xor(ll *a,int opt)
{
    for(int i=1;i=0;j--){
            if(b[j]){
                ans[i] = j;
                break;
            }
        }
    }
    for(int i=21;i<=n;i++) ans[i] = ans[i-2];
    for(int i=1;i<=n;i++){
        if(i>1) printf(" ");
        printf("%d",ans[i]);
    }
}

Fake Maxpooling

签到,模拟,优化

题意

给定一个 n ∗ m n*m nm的矩阵,第 ( i , j ) (i,j) (i,j)个位置的值为 l c m ( i , j ) lcm(i,j) lcm(i,j),有一个 k ∗ k k*k kk的框在矩阵内移动,求这个框在所有位置的最大值的和

解法

g c d gcd gcd写记忆化,滑动窗口维护最大值

Greater and Greater

b i t s e t bitset bitset 优化

题意

给你一个长度为n的序列A,和一个长度为m的序列B,求有多少长为m的A的子序列S,满足 ∀ i ∈ { 1 , 2 , . . . m } , S i > B i \forall i\in\{1,2,...m\},S_i>B_i i{1,2,...m},Si>Bi

解法

2020牛客多校第二场训练补题记录_第1张图片

#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
#define pi 3.1415926535
using namespace std;
int n,m;
int a[150005];
struct nd{
    int val,id;
}b[40005];
bitset<40005> s,ss[40005],cur;
int fd(int x){
    int l = 0,r = m;
    while(l>1;
        if(b[mid].val> x) r = mid;
        else l = mid+1;
    }
    return l;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i

Happy Triangle

数据结构

题意

给你一个multiset,三个操作,操作一为插入一个元素x,操作二为删除一个元素x,操作三位判断multiset中是否有两个数与x构成一个不退化三角形

解法

判断能否构成三角形,有两种情况,一是x为最长边,则存在两条边 a + b > x a+b>x a+b>x使用小于等于x的最大的两条边判断即可,这里可以用set+map维护,set存在集合中的数,map存各个数的数量。

二是x为非最长边,即存在 a − b < x a-bab<x ,可以使用权值线段树维护,对每个权值,线段树维护集合中他与前一个值的差,若存在多个即为0,没有前置或不在集合中则为INF。

#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
#define pi 3.1415926535
using namespace std;
const int INF = 2*inf;
const int maxn = 2e5+5;
struct ask{
    int op,x;//,id;
}a[maxn];
int b[maxn],q,m;
set s;
map mp;
struct stree{
    int l,r;
    int val;
}t[maxn<<2];
void pushup(int x){
    t[x].val = min(t[x<<1].val,t[x<<1|1].val);
}
void build(int x,int l,int r){
    t[x].l = l,t[x].r = r;
    if(l == r){
        t[x].val = INF;
        return;
    }
    int mid = (t[x].l+t[x].r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    pushup(x);
}
void change(int x,int p,int val){
    if(t[x].l == t[x].r){
        t[x].val = val;
        return;
    }
    int mid = (t[x].l+t[x].r)>>1;
    if(p<=mid) change(x<<1,p,val);
    else change(x<<1|1,p,val);
    pushup(x);
}
int query(int x,int l,int r){
    if(t[x].l>=l && t[x].r<=r){
        return t[x].val;
    }
    int mid = (t[x].l+t[x].r)>>1;
    int res = INF;
    if(mid>=l) res = min(res,query(x<<1,l,r));
    if(mid1){
                    mx += *it;
                }else{
                    it--;
                    mx += *it;
                    if(*it == -1)
                        f=0;
                }
            }
            if(mx > x && f){
                puts("Yes");
            }else{
                int mn = query(1,p,m);
                if(x>mn){
                    puts("Yes");
                }else{
                    puts("No");
                }
            }
        }
    }
}

Interval

网格网络流

题意

给你元组(l,r),可以进行缩减和扩张操作,你可以花一些费用禁止一些操作。求最小的费用使得 l ! = r l!=r l!=r.

解法

裸的网格图网络流,对偶图最短路=最小割

#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
using namespace std;
const int N=500010;
vector ver[N],edge[N];
ll d[N];//到起点的距离
bool v[N];
int n,m,s,t;
priority_queue > q;//第一维为-d[x],第二维为x
void dijkstra(){
    memset(d,0x3f,sizeof(d));
    d[s]=0;
    q.push(make_pair(0,s));
   // cout<d[x]+z){
                d[y]=d[x]+z;
                q.push(make_pair(-d[y],y));
            }
        }
    }
}
void add(int x,int y,ll w){
    ver[x].pb(y),ver[y].pb(x);
    edge[x].pb(w),edge[y].pb(w);
}
int id[505][505];
int tot;
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i= d[N-1]){
        puts("-1");
    }else{
        printf("%lld\n",d[t]);
    }
}

Just Shuffle

数学

题意

给定一个 1 1 1~ n n n的排列A,求一个置换B,使得 1 , 2 , 3... n {1,2,3...n} 1,2,3...n经过k轮置换变成A

解法

对每个环,长度为r,即周期为r,假设{ a 1 , a 2 . . . , a r a_1,a_2...,a_r a1,a2...,ar}( a 1 < a 2 < . . . < a r a_1a1<a2<...<ar)表示为 A m A^m Am, 故 ( A m ) k = A k m = A (A^m)^k = A^{km} = A (Am)k=Akm=A,即 k m % r = 1 km\%r=1 km%r=1 故 m为模r意义下 k − 1 k^{-1} k1,答案为 A m + 1 A^{m+1} Am+1

#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
#define pi 3.1415926535
using namespace std;
const int N = 1e5+5;
int a[N],used[N],ans[N],tmp[N];
vector seq;
int n,m;
ll ex_gcd(ll a, ll b, ll &x, ll &y) {
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    else {
        ll r = ex_gcd(b, a % b, y, x);
        y -= x * (a / b);
        return r;
    }
}
ll inv(ll a, ll p) {//a在模p意义下的逆元若gcd(a,p)!=1,逆元不存在
    ll x, y;
    ex_gcd(a, p, x, y);
    x = (x % p + p) % p;
    return x;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){
        if(!used[i]){//若之前已经出现在某个环上不操作
            seq.clear();
            int now = i;
            //找环
            while(!used[now]){
                seq.pb(now);
                used[now] = 1;
                now = a[now];
            }
            int k = inv(m%seq.size(),seq.size());
            for(int j=0;j1) printf(" ");
        printf("%d",ans[i]);
    }
    return 0;
}

Keyboard Free

期望,积分,计算几何

题意

给你三个同心圆,从各圆中任取一点,求这三个点构成三角形面积的期望

解法

固定A点,枚举B点。AB都固定的情况下显然可以积分算出ABC三角形以AB为底的高的期望

2020牛客多校第二场训练补题记录_第2张图片

对于一个固定的 AB,我们可以求出线段长度 L 以及它与圆心的距离 H 和夹角 α ,显然有 a l p h a < π 2 alpha < \frac{\pi}{2} alpha<2π
接着通过积分求出 C 点运动时这个三角形的期望高,我们将其分成三部分。
s u m 1 = ∫ 0 π ( H + r 3 × s i n ( x ) ) d x = π H + r 3 × ∫ 0 π s i n ( x ) d x = π H + 2 × r 3 sum_1=\int_{0}^{\pi}(H+r3\times sin(x))dx=\pi H + r3\times \int_{0}^{\pi}sin(x)dx=\pi H+2\times r3 sum1=0π(H+r3×sin(x))dx=πH+r3×0πsin(x)dx=πH+2×r3

s u m 2 = 2 ∫ 0 α ( H − r 3 × s i n ( x ) ) d x = 2 ( H α − r 3 ∫ 0 α s i n ( x ) d x ) = 2 ( α H + r 3 × c o s ( α ) − r 3 ) sum_2=2\int_{0}^{\alpha}(H-r3\times sin(x))dx=2(H\alpha - r3\int_{0}^{\alpha}sin(x)dx)=2(\alpha H +r3\times cos(\alpha)-r3) sum2=20α(Hr3×sin(x))dx=2(Hαr30αsin(x)dx)=2(αH+r3×cos(α)r3)

s u m 3 = ∫ α π − α ( r 3 × s i n ( x ) − H ) d x = r 3 ∫ α π − α s i n ( x ) d x − ( π − 2 α ) H = 2 r 3 × c o s ( α ) − ( π − 2 α ) H sum_3=\int_{\alpha}^{\pi-\alpha}(r3\times sin(x)-H)dx=r3\int_{\alpha}^{\pi-\alpha}sin(x)dx-(\pi-2\alpha)H=2r3\times cos(\alpha)-(\pi-2\alpha)H sum3=απα(r3×sin(x)H)dx=r3απαsin(x)dx(π2α)H=2r3×cos(α)(π2α)H


s u m = π H + 2 × r 3 + 2 ( α H + r 3 × c o s ( α ) − r 3 ) + 2 r 3 × c o s ( α ) − ( π − 2 α ) H = 4 r 3 × c o s ( α ) + 4 α × H sum=\pi H+2\times r3+2(\alpha H +r3\times cos(\alpha)-r3)+2r3\times cos(\alpha)-(\pi-2\alpha)H=4r3\times cos(\alpha)+4\alpha\times H sum=πH+2×r3+2(αH+r3×cos(α)r3)+2r3×cos(α)(π2α)H=4r3×cos(α)+4α×H
所以期望高度 h = 4 r 3 × c o s ( α ) + 4 α × H 2 π h=\frac{4r3\times cos(\alpha)+4\alpha\times H}{2\pi} h=2π4r3×cos(α)+4α×H,期望面积为 h × L 2 \frac{h\times L}{2} 2h×L

在圆周上均匀取1000个B点即可

#include
#define ll long long
#define ull unsigned long long
#define pb push_back
#define lowbit(x) ((x)&(-x))
#define inf 0x3f3f3f3f
#define endl "\n"
#define MP(x,y) (make_pair(x,y))
#define pii pair
#define pll pair
using namespace std;
const double pi = acos(-1.0);
int t;
int r1,r2,r3;
double f(double x){
    return x*x;
}
void gao(){
    scanf("%d%d%d",&r1,&r2,&r3);
    if (r1 > r2) swap(r1, r2);
    if (r1 > r2) swap(r1, r3);
    if (r2 > r3) swap(r2, r3);
    double ans = 0;
    for(int i=1;i<=1000;i++){
        double sina = sin(2.0 * pi / 1000.0 * i);
        double cosa = cos(2.0 * pi / 1000.0 * i);
        double x = r2*cosa,y = r2*sina;
        double l = sqrt(f(x-r1)+f(y));
        double h = y/l*r1;
        double alpha = asin(h/r3);
        double H = (4.0*r3*cos(alpha) + 4.0*alpha*h)/(2.0*pi);
        ans += H*l/2;
    }
    ans /= 1000.0;
    printf("%.1f\n",ans);
}
int main(){
    scanf("%d",&t);
    while(t--){
        gao();
    }
}

你可能感兴趣的:(刷题记录)