10.22 模拟赛

Posted yijan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10.22 模拟赛相关的知识,希望对你有一定的参考价值。

10.22 模拟赛

T1 染色

考虑每个连通块删成一棵树就好了。

mmp场上就我路径压缩写炸。。。。

#include<iostream>
#define MAXN 200006
using namespace std;
int n , m;
int fa[MAXN] , siz[MAXN] , book[MAXN] , sz[MAXN];
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
int main() {
    cin >> n >> m;
    for( int i = 1 ; i <= n ; ++ i ) sz[i] = 1 , fa[i] = i;
    for( int i = 1 , u , v ; i <= m ; ++ i ) {
        scanf("%d%d",&u,&v);
        if(find(u) != find(v))
            siz[find(u)] += siz[find(v)] + 1 , sz[find(u)] += sz[find(v)] , fa[find(v)] = find(u);
        else siz[find(u)] ++;
    }
    int res = 0;
    for( int i = 1 ; i <= n ; ++ i ) if( !book[find(i)] && siz[find(i)] )
        book[find(i)] = 1 , res += siz[find(i)] - ( sz[find(i)] - 1 );
    cout << res << endl;
}

T2 乘方

首先,二分答案,变成一个判定问题。

如果只有一个集合,比一个数字小的数字个数就是 $ sqrt[n]{m} $

然后如果是一些集合交,可以直接把这些集合取 $ lcm $ ,可以证明是对的。

然后可以 $ 2^k $ 枚举子集容斥

当然,这个容斥看起来就可以dp

然后dp就对了,设 $ dp[i][j] $ 表示前 i 个数,LCM为一个 j 的子集的容斥系数

记得开根号二分。。不然T惨

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define int long long
#define MAXN 62
typedef long long ll;
int fuck[MAXN][MAXN];
inline int gcd( int a , int b ) { return b ? gcd( b , a % b ) : a; }
inline int lcm( int x , int y ) { 
if (fuck[x][y]) return fuck[x][y];
return fuck[x][y] = fuck[y][x] = x * y / gcd( x , y ); 
}
int m , k;
int A[MAXN];
int dp[MAXN][MAXN];

inline ll calc(ll n, int k)
{
    ll val = 1;
    for (int i = 0; i < k; i++)
    {
        if ((double)val * n >= 100000000000000000LL)
            return 100000000000000000LL;
        val *= n;
    }
    return val;
}
inline ll sqrt(ll n, int k)
{
    ll res = std::pow(n, 1.0 / k);
    while (calc(res, k) < n)
        res++;
    while (calc(res, k) > n)
        res--;
    return res - 1;
}
int qpow(int x,int y)
{
    int res=1;
    while(y)
    {
        if(y&1)
        {
            if(res*x<=0||res*x>1e17)return -1;
            res*=x;
        }
        y>>=1;
        if(!y)break;
        if(x*x<=0||x*x>1e17)return -1;
        x*=x;
    }
    return res;
}
int lim[MAXN];
int get(int x,int v)
{
    int l=1,r=lim[x],res=1;
    if(x>60)return 1;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        int re=qpow(mid,x);
        if(re<=v&&(re!=-1))res=mid,l=mid+1;
        else r=mid-1;
    }
    return res;
}
inline bool chk( int x ) {
    long long res = 0;
    for( int n = 1 ; n < MAXN ; ++ n )
        res += dp[k][n] * get( n , x ) - dp[k][n];
//  cout << res << endl;
    return res >= m;
}
signed main() {
    lim[2]=1e9;lim[3]=1e6;lim[4]=sqrt(lim[2])+15;lim[5]=4500;lim[6]=2000;
    for(int i=7;i<=60;++i)
    {
        for(int j=1;;++j)
        {
            int now=qpow(j,i);
            if(now==-1)break;
            lim[i]=j;
        }
    }
    int t; cin >> t;
    while( t-- ) {
        scanf("%lld%lld",&m,&k), m--;
        int flag = 0;
        for( int i = 1 ; i <= k ; ++ i ) { scanf("%lld",&A[i]); if( A[i] == 1 ) flag = 1; }
        if( flag ) { cout << m + 1 << endl; continue; }
        memset( dp , 0 , sizeof dp );
        dp[1][A[1]] = 1;
        for( int i = 1 ; i < k ; ++ i ) {
            dp[i + 1][A[i + 1]] = 1;
            for( int n = 1 ; n < MAXN ; ++ n ) if (dp[i][n]) {
                dp[i + 1][n] += dp[i][n];
                if( lcm(n, A[i + 1]) < MAXN )
                    dp[i + 1][lcm(n, A[i + 1])] -= dp[i][n];
            }
        }
//      for (int i = 2; i <= 50; i++)
//          cout << dp[k][i][0] - dp[k][i][1] << ' ';
//      cout << endl;
//      chk(64);
        ll l = 1 , r = 100000000000000006LL, ans = -1;
        while( l <= r ) {
            int mid = l + r >> 1;
            if( chk( mid ) ) ans = mid, r = mid - 1;
            else l = mid + 1;
        }
        cout << ans << endl;
    }
}

T3 位运算

and 可以用 这里 的 F 的做法来做,复杂度 $ O(n + v) $ 当然也可以贪心 $ O(nlogv) $

xor 可以用trie直接做

or 不会。貌似只能FWT

所以就粘板子 FWT 跑就行了,直接求位运算卷积就做完了。

当 FWT 板子放在这里把

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
using namespace std;
//#define int long long
typedef long long ll;
#define MAXN 8388610 
#define MAXV 8388610
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define inf 0x3f3f3f3f
#define cmx( a , b ) a = max( a , b )
#define cmn( a , b ) a = min( a , b )
#define upd( a , b ) ( a = ( a + b ) % P )
#define swap( a , b ) a = a ^ b , b = a ^ b , a = a ^ b
#define P 1000000007
int n , q;
int A[MAXN];

namespace fwt {
    
    inline void FWT1(ll a[], int len) {
        for (int mid = 2; mid <= len; mid <<= 1) 
            for (int i = 0; i < len; i += mid)
                for (int j = i; j < i + (mid >> 1); j++) 
                    a[j + (mid >> 1)] += a[j];
    }
    
    inline void IFWT1(ll a[], int len) {
        for (int mid = 2; mid <= len; mid <<= 1) 
            for (int i = 0; i < len; i += mid)
                for (int j = i; j < i + (mid >> 1); j++) 
                    a[j + (mid >> 1)] -= a[j];
    }
    
    inline void FWT2(ll a[], int len) {
        for (int mid = 2; mid <= len; mid <<= 1) 
            for (int i = 0; i < len; i += mid)
                for (int j = i; j < i + (mid >> 1); j++) 
                    a[j] += a[j + (mid >> 1)];
    }
    
    inline void IFWT2(ll a[], int len) {
        for (int mid = 2; mid <= len; mid <<= 1) 
            for (int i = 0; i < len; i += mid)
                for (int j = i; j < i + (mid >> 1); j++) 
                    a[j] -= a[j + (mid >> 1)];
    }
    
    inline void FWT3(ll a[], int len) {
        for (int mid = 2; mid <= len; mid <<= 1) 
            for (int i = 0; i < len; i += mid)
                for (int j = i; j < i + (mid >> 1); j++) {
                    ll x = a[j], y = a[j + (mid >> 1)];
                    a[j] = x + y, a[j + (mid >> 1)] = x - y;
                }
    }
    
    inline void IFWT3(ll a[], int len) {
        for (int mid = 2; mid <= len; mid <<= 1) 
            for (int i = 0; i < len; i += mid)
                for (int j = i; j < i + (mid >> 1); j++) {
                    ll x = a[j], y = a[j + (mid >> 1)];
                    a[j] = (x + y) >> 1, a[j + (mid >> 1)] = (x - y) >> 1;
                }
    }
    
    ll a[MAXN], b[MAXN]; int input[400010];
    
    int main() {
        int mx = 0, len = 1; 
        for (int i = 1, x; i <= n; i++) 
            a[A[i]]++, b[A[i]]++, mx = max(mx, A[i]), input[i] = A[i];
        while (len <= mx) len <<= 1;
        if (q == 1) {
            FWT2(a, len);
            for (int i = 0; i < len; i++) a[i] = a[i] * a[i];
            IFWT2(a, len);
            for (int i = len - 1; i >= 0; i--) if (a[i]) {
                ll res = (a[i] - b[i]) >> 1;
                if (res) return printf("%d %lld", i, res), 0;
            }
        } else if (q == 2) {
            bool flag = true;
            for (int i = 2; i <= n; i++) 
                if (input[i] != input[1]) {
                    flag = false; break;
                }
            if (flag) return printf("0 %lld", (ll)n * (n + 1) / 2), 0;
            FWT3(a, len);
            for (int i = 0; i < len; i++) a[i] = a[i] * a[i];
            IFWT3(a, len);
            for (int i = len - 1; i >= 0; i--) if (a[i]) 
                return printf("%d %lld", i, a[i] >> 1), 0;
        } else {
            FWT1(a, len);
            for (int i = 0; i < len; i++) a[i] = a[i] * a[i];
            IFWT1(a, len);
            for (int i = len - 1; i >= 0; i--) if (a[i]) {
                ll res = (a[i] - b[i]) >> 1;
                if (res) return printf("%d %lld", i, res), 0;
            }
        }
    }

}


int main() {
    cin >> n >> q;
    int mx = 0;
    for( int i = 1 ; i <= n ; ++ i ) scanf("%d",&A[i]) , mx = max(A[i] , mx);
    fwt::main();
    
}

以上是关于10.22 模拟赛的主要内容,如果未能解决你的问题,请参考以下文章

10.22总结

lecture 10.22

10.22第12天

10.22 simulated match

7.16 10.19-10.22

10.22 信号名称与编号