8.9日总结

题赛地址


C题:(三元环计数) 
题意,给定一个图,求四元环的个数,这个四元环要求是由两个三元环相邻一条共同边组成的

解法: 
①统计每个点的度数 
②入度<=sqrt(m)的分为第一类,入度>sqrt(m)的分为第二类 
③对于第一类,暴力每个点,然后暴力这个点的任意两条边,再判断这两条边的另一个端点是否连接 
因为m条边最多每条边遍历一次,然后暴力的点的入度<=sqrt(m),所以复杂度约为O(msqrt(m)) 
④对于第二类,直接暴力任意三个点,判断这三个点是否构成环,因为这一类点的个数不会超过sqrt(m)个,所以复杂度约为O(sqrt(m)3)=O(msqrt(m)) 
⑤判断两个点是否连接可以用set,map和Hash都行,根据具体情况而行 
这种做法建的是双向边,常数很大

//https://www.cnblogs.com/jiachinzhao/p/7474761.html
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
sets;
int deg[maxn];
vectorg[maxn];
int vis[maxn], vi[maxn];

int main() {
    int n, m, u, v, sz;
    while (scanf("%d%d", &n, &m) != EOF) {
        sz = sqrt(m + 0.5);
        s.clear();
        for (int i = 1; i <= n; i++) {
            vis[i] = vi[i] = deg[i] = 0;
            g[i].clear();
        }
        for (int i = 0; i < m; i++) {
            scanf("%d%d", &u, &v);
            s.insert(u + 1ll * v*n);
            s.insert(v + 1ll * u*n);
            deg[u]++, deg[v]++;
            g[u].push_back(v); g[v].push_back(u);
        }
        ll ans = 0;
        for (int u = 1; u <= n; u++) {
            vis[u] = 1;
            for (auto v : g[u])vi[v] = u;
            for (auto v : g[u]) {
                int cnt = 0;
                if (vis[v])continue;
                if (deg[v] <= sz) {
                    for (auto vv : g[v])
                        if (vi[vv] == u)cnt++;
                }
                else {
                    for (auto vv : g[u]) {
                        if (s.find(1ll * v*n + vv) != s.end())cnt++;
                    }
                }
                ans += 1ll * cnt*(cnt - 1) / 2;
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

D(矩阵快速幂) 
题意:有一个4*n的矩阵,要求只能只能用2x1的木板覆盖,问一共有多少种覆盖的方法

解法: 
当前一列已经铺满的时候,那么下一列一共有五种铺法,根据这五种铺发推出递推关系式,之后矩阵快速幂跑一下即可 
博客链接


//https://blog.csdn.net/elbadaernu/article/details/77825979

#include  
#include 
#include 
using namespace std;
#define LL long long 
const int mod = 1000000007;
struct matrix
{
    LL x[4][4];
};
matrix mutimatrix(matrix a, matrix b)
{
    matrix temp;
    memset(temp.x, 0, sizeof(temp.x));
    for (int i = 0; i < 4; i++)
        for (int j = 0; j < 4; j++)
            for (int k = 0; k < 4; k++)
            {
                temp.x[i][j] += a.x[i][k] * b.x[k][j];
                temp.x[i][j] %= mod;
            }
    return temp;
}

matrix k_powmatrix(matrix a, LL n)//矩阵快速幂
{
    matrix temp;
    memset(temp.x, 0, sizeof(temp.x));
    for (int i = 0; i < 4; i++)
        temp.x[i][i] = 1;

    while (n)
    {
        if (n & 1)
            temp = mutimatrix(temp, a);

        a = mutimatrix(a, a);
        n >>= 1;
    }
    return temp;
}


int main(){
    LL n;
    while (scanf("%lld", &n) != EOF){
        //前面四个手算下
        if (n == 1){printf("1\n");continue;}
        if (n == 2){printf("5\n");continue;}
        if (n == 3){printf("11\n");continue;}
        if (n == 4){printf("36\n");continue;}

        matrix st;
        memset(st.x, 0, sizeof(st.x));
        st.x[0][0] = 1;
        st.x[1][0] = 5;
        st.x[2][0] = 1;
        st.x[3][0] = -1;

        st.x[0][1] = 1;
        st.x[1][2] = 1;
        st.x[2][3] = 1;

        matrix init;//初始矩阵
        memset(init.x, 0, sizeof(init.x));

        init.x[0][0] = 36;
        init.x[0][1] = 11;
        init.x[0][2] = 5;
        init.x[0][3] = 1;

        st = k_powmatrix(st, n - 4);//经过n-4次相乘
        st = mutimatrix(init, st);//然后再乘上初始矩阵

        printf("%lld\n", (st.x[0][0] + mod) % mod);
    }
    return 0;
}

E: 
题意: 
有一列数,每次询问随机的删掉一个数,求最后所有数且、或、异或的结果

解法: 
按位处理,每一位统计一的个数,之后按一的个数为0,为1,为n,以及其他情况分类讨论即可


#include
#include
using namespace std;
const int maxn = 1e6 + 5;

int n, m;
int a[maxn];
int b[maxn];

int main() {
    while (~scanf("%d %d", &n, &m)) {
        memset(a, 0, sizeof(a)); 
        memset(b, 0, sizeof(b));

        int AND = 0, OR = 0, XOR = 0;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            int t = a[i], k = 0;
            XOR ^= a[i];
            while (t) { b[k++] += t % 2; t /= 2; }
        }

        while (m--){
            int x; scanf("%d", &x);
            x = a[x];
            int NXOR = XOR^x;
            AND = 0, OR = 0;
            for (int j = 0; j < 32; j++) {
                if (b[j] == 0)continue;
                else if (b[j] == 1) {
                    if (x&(1 << j))continue;
                    OR += (1 << j);
                    if (n == 2)AND += (1 << j);
                }
                else if (b[j] == n) {
                    AND += (1 << j); OR += (1 << j);
                }
                else {
                    OR += (1 << j);
                    if (b[j] == n - 1 && !(x&(1 << j)))
                        AND += (1 << j);
                }
            }
            printf("%d %d %d\n", AND, OR, NXOR);
        }
    }
    return 0;
}

H:(打表+数论) 
题意: 
给定一个数n和a,问在 [1,1 << n] 的范围内有多少个b满足 a^b=b^a(mod 1 << n)

解法: 
关键是思路! 

8.9日总结_第1张图片

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXM=100010;
const long long MOD=1000000007;
const double PI=acos(-1);

long long n,a;

long long qpow(long long x,long long y,long long mod)
{
    long long res=1;
    while(y)
    {
        if (y&1) res=(res*x)%mod;
        x=(x*x)%mod;
        y=y>>1;
    }
    return res;
}
long long qpow(long long x,long long y)
{
    long long res=1;
    while(y)
    {
        if (y&1) res=res*x;
        x=x*x;
        y=y>>1;
    }
    return res;
}
int main()
{
    while(scanf("%lld%lld",&n,&a)!=EOF)
    {
        if (a&1)
        {
            printf("1\n");
            continue;
        }
        else
        {
            long long m=1<

 

你可能感兴趣的:(2018暑假ACM集训)