zoukankan      html  css  js  c++  java
  • [2020牛客NOIP赛前集训营-提高组(第三场)] 补题

    A.牛半仙的妹子数

    Problem

    题目链接

    Soluiton

    • 思维 / 数学

    首先观察到左边的数之和为 (a+b),令其为 (x),右边的数为 (c),令其为 (y)。并且左边加右边的和为定值 (a+b+c),令 (s=a+b+c)

    (x+y = s)

    如果 (x>y),则 (x = x - y,y = 2y)。此时 (2y<s),所以 (2yequiv 2y pmod{s}) (1)(可能看起来有点别扭)

    否则 (x le y),则 (x = 2x, y = y - x)。此时 (2y>s,y = y - x = y - s + y = 2y-s),所以 (2y equiv 2y-s pmod{s}) (2)。

    又因为在 (1) 式中 (0 le 2y < s),在 (2) 式中 (0 le 2y-s < s),我们可以认为答案就是 (2^ky mod s)

    用快速幂,时间复杂度 (O(T log k))

    Code

    Talk is cheap.Show me the code.

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
        return x * f;
    }
    int a,b,c,k,mod;
    int Pow(int x,int y) {
    	int res = 1, base = x;
    	while(y) {
    		if(y&1) res = res*base%mod; base = base*base%mod; y >>= 1;
    	}
    	return res;
    }
    void work() {
    	a = read(), b = read(), c = read(), k = read();
    	mod = a + b + c;
    	printf("%lld
    ",Pow(2,k)*c%mod);
    }
    signed main()
    {
    	int T = read();
    	while(T--) work();
       	return 0;
    }
    

    B.牛半仙的妹子图

    Problem

    题目地址

    Solution

    • SPFA

    本题是稀疏图(ygt大佬说网格图是稀疏图可以卡掉SPFA),可以用 SPFA 处理从 s 到 i 的所有路径里面最大边最小是多少,记为 dismx[ i ]。然后按照题意模拟,统计一下答案,输出即可。时间复杂度 (O(km + q log 600))(O(km)) 是SPFA的复杂度,可以过)

    Code

    Talk is cheap.Show me the code.

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
        return x * f;
    }
    const int N = 5e5+7, M = 607;
    int n,m,q,s,mod,opt,cnt,tot,ntmp;
    int c[N],head[N],dismx[N],ma[M],sum[M],cal[M],btmp[N];
    bool flag[N];
    struct Edge {
    	int next,to,w;
    }edge[N<<1];
    void add(int u,int v,int w) {
    	edge[++cnt] = (Edge)<%head[u],v,w%>;
    	head[u] = cnt;
    }
    void SPFA() {
    	bool vis[N];
    	queue<int> q;
    	memset(dismx, 0x3f, sizeof(dismx));
    	memset(vis, 0, sizeof(vis));
    	dismx[s] = 0; q.push(s); vis[s] = 1;
    	while(!q.empty()) {
    		int u = q.front(); vis[u] = 0; q.pop();
    		//if(u == n) printf("??? %d ???
    ",dismx[u]);
    		for(int i=head[u];i;i=edge[i].next) {
    			int v = edge[i].to, w = edge[i].w;
    			if(dismx[v] > max(dismx[u],w)) {
    				dismx[v] = max(dismx[u],w);
    				if(!vis[v]) {
    					q.push(v); vis[v] = 1;
    				}
    			}
    		}
    	}
    }
    int Get1(int x) {
    	int l = 1, r = ntmp, mid, ans = ntmp + 1;
    	while(l <= r) {
    		mid = (l + r) >> 1;
    		if(btmp[mid] >= x) {
    			ans = mid; r = mid - 1;
    		} else l = mid + 1;
    	}
    	return ans;
    }
    int Get2(int x) {
    	int l = 1, r = ntmp, mid, ans = 0;
    	while(l <= r) {
    		mid = (l + r) >> 1;
    		if(btmp[mid] <= x) {
    			ans = mid; l = mid + 1;
    		} else r = mid - 1;
    	}
    	return ans;
    }
    signed main()
    {
    	//freopen("sample.in","r",stdin);
    	//freopen("x.txt","w",stdout);
    	n = read(), m = read(), q = read(), s = read(), opt = read();
    	if(opt == 1) mod = read();
    	for(int i=1;i<=n;++i) c[i] = read();
    	for(int i=1;i<=m;++i) {
    		int u = read(), v = read(), w = read();
    		add(u,v,w), add(v,u,w);
    	}
    	SPFA();
    	/*cout << "dismx" << endl;
    	for(int i=1;i<=n;++i) printf("%d ",dismx[i]);
    	cout << endl << endl;*/
    	memset(ma, 0x3f, sizeof(ma));
    	int INF = ma[0];
    	for(int i=1;i<=n;++i) {
    		ma[c[i]] = min(ma[c[i]], dismx[i]);
    		if(!flag[c[i]] && dismx[i]!=INF) {
    			++tot; flag[c[i]] = 1;
    		}
    	}
    	sort(ma+1, ma+1+600);
    	for(int i=1;i<=600;++i) btmp[i] = ma[i];
    	ntmp = unique(btmp+1, btmp+1+tot) - btmp - 1;
    	for(int i=1;i<=tot;++i) {
    		int x = lower_bound(btmp+1, btmp+1+ntmp, ma[i]) - btmp;
    		//printf("%d ",x);
    		++cal[x];
    	}
    	/*printf("btmp-ma:
    ");
    	for(int i=1;i<=ntmp;++i) printf("%d ",btmp[i]);
    	cout << endl;
    	printf("cal:
    ");
    	for(int i=1;i<=ntmp;++i) printf("%d ",cal[i]);
    	cout << endl;*/
    	for(int i=1;i<=ntmp;++i) cal[i] += cal[i-1];
    	for(int i=1;i<ntmp;++i) sum[i] = sum[i-1] + cal[i]*(btmp[i+1]-btmp[i]);
    	/*printf("sum:
    ");
    	for(int i=1;i<ntmp;++i) printf("%d ",sum[i]);
    	cout << endl << endl;*/
    	int ans = 0;
    	while(q--) {
    		int l = read(), r = read();
    		if(opt == 1) {
    			l = (l xor ans) % mod + 1;
    			r = (r xor ans) % mod + 1;
    			if(l > r) swap(l, r);
    		}
    		ans = 0;
    		int ml = Get1(l), mr = Get2(r);
    		//printf(" %d %d
    ",ml,mr);
    		if(mr == 0) ans = 0;
    		else if(ml == ntmp+1) ans = (r - l + 1) * tot;
    		else {
    			//printf(" %d %d
    ",ml,mr);
    			ans += (btmp[ml] - l) * (cal[ml-1]);
    			ans += (sum[mr-1] - sum[ml-1]);
    			ans += (r - btmp[mr]+1) * cal[mr];
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    /*
    8 15 1 1 0
    4 3 4 2 3 1 2 1 
    1 2 7
    1 3 6
    1 4 6
    3 5 13
    1 6 13
    5 7 8
    4 8 15
    4 3 15
    7 3 9
    2 4 13
    6 7 7
    8 1 5
    5 8 14
    6 8 3
    6 5 5
    0 27
    
    96
    */
    

    C.牛半仙的妹子Tree

    Problem

    题目链接

    Solution

    • ST表求LCA((O(n log n)) 预处理,(O(1)) 查询,常数较大)

    • 操作分块思想

    以清空操作为分界点,把操作序列分成 (k) 块。

    1. 对于一个大小为 s 的块,且用 lca法 判断查询操作:最劣的情况下有 (frac{s}{2}) 个加入操作,(frac{s}{2}) 个查询操作,lca法 判断一个点的复杂度是 (O(1)),故判断 (frac{s}{2}) 个点的复杂度是 (O(frac{s}{2})),该块的所有操作复杂度 (O(frac{s^2}{4})),由于 lca法 的常数较大,可以把复杂度近似为 (O(s^2))

    2. 对于一个大小为 s 的块,且用 bfs法 判断查询操作:复杂度 (O(n))

    对于以上两种方法的分析,于是我们可以:

    对于一个大小大于 (sqrt{m}) 的块,用 bfs法 判断查询操作,块内总复杂度 (O(n)),均摊到每个查询操作上 (O(sqrt{n}))

    对于一个大小小于 (sqrt{m}) 的块,有 lca法 判断查询操作,每个查询操作复杂度 (O(sqrt{m}))

    对于所有查询操作,总时间复杂度 (O(nsqrt{n})) 级别。(n le 10^5),可以通过。

    Code

    Talk is cheap.Show me the code.

    #include<bits/stdc++.h>
    #define mp make_pair
    #define fi first
    #define se second
    #define pb push_back
    using namespace std;
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
        return x * f;
    }
    typedef pair<int,int> PII;
    const int N = 1e5+7;
    int n,m,cnt,dcnt,qcnt;
    int head[N],dep[N],dfn[N<<1],pos[N],ST[N<<1][20],lg[N<<1],opt[N],X[N],qs[N],qt[N],id[N<<1];
    vector<int> ans;
    struct Edge {
        int next,to;
    }edge[N<<1];
    inline void add(int u,int v) {
        edge[++cnt] = (Edge)<%head[u],v%>;
        head[u] = cnt;
    }
    void Dfs(int u,int fa) {
        dep[u] = dep[fa] + 1;
        ++dcnt; dfn[dcnt] = dcnt; pos[u] = dcnt; id[dcnt] = u;
        for(int i=head[u];i;i=edge[i].next) {
            int v = edge[i].to;
            if(v != fa) {
                dfn[++dcnt] = pos[u]; Dfs(v,u);
            }
        }
    }
    void Init() {
        for(int i=2;i<=dcnt;++i) lg[i] = lg[i>>1] + 1;
        for(int i=1;i<=dcnt;++i) ST[i][0] = dfn[i];
        for(int j=1;j<20;++j) {
            for(int i=1;i+(1<<j)-1<=dcnt;++i) {
                ST[i][j] = min(ST[i][j-1], ST[i+(1<<(j-1))-1][j-1]);
            }
        }
    }
    int dist(int x,int y) {
        int px = pos[x], py = pos[y];
        if(px > py) swap(px,py);
        int L = py - px + 1;
        int lca = id[min(ST[px][lg[L]], ST[py-(1<<lg[L])+1][lg[L]])];
        return dep[x] + dep[y] - 2*dep[lca];
    }
    void Calc1(int s,int t) {
        vector<PII> ma;
        for(int i=s;i<t;++i) {
            if(opt[i] == 1) {
                ma.pb(mp(X[i],i));
            } else {
                bool flag = 0;
                for(int k=0;k<ma.size();++k) {
                    if(dist(ma[k].fi, X[i]) <= i-ma[k].se) {
                        flag = 1; break;
                    }
                }
                ans.pb(flag);
            }
        }
    }
    void Calc2(int s,int t) {
        bool vis[N]; queue<int> q;
        memset(vis, 0, sizeof(vis));
        for(int i=s;i<t;++i) {
            int step = q.size();
            while(step--) {
                int u = q.front(); q.pop();
                for(int i=head[u];i;i=edge[i].next) {
                    int v = edge[i].to;
                    if(!vis[v]) {
                        vis[v] = 1; q.push(v);
                    }
                }
            }
            if(opt[i] == 1) vis[X[i]] = 1, q.push(X[i]);
            else ans.pb(vis[X[i]]);
        }
    }
    int main()
    {
        n = read(), m = read();
        for(int i=1;i<n;++i) {
            int u = read(), v = read();
            add(u,v), add(v,u);
        }
        //cout << endl;
        Dfs(1,0); Init();
        qs[++qcnt] = 1;
        for(int i=1;i<=m;++i) {
            opt[i] = read(), X[i] = read();
            if(opt[i] == 2) {
                qt[qcnt] = i; qs[++qcnt] = i + 1;
            }
        }
        qt[qcnt] = m + 1;
        //cout << endl;
        //for(int i=1;i<=qcnt;++i) printf("%d %d
    ",qs[i],qt[i]);
        for(int i=1;i<=qcnt;++i) {
            int qn = qt[i] - qs[i];
            if(qn <= sqrt(m)) {
                //puts("test");
                Calc1(qs[i], qt[i]);
            } else {
                Calc2(qs[i], qt[i]);
            }
        }
        for(int i=0;i<ans.size();++i) {
            if(ans[i] == 1) puts("wrxcsd");
            else puts("orzFsYo");
        }
        return 0;
    }
    /*
    5 4
    1 2
    1 3
    2 4
    2 5
    1 2
    3 2
    2 4
    3 4
     
    wrxcsd
    orzFsYo
    */
    
  • 相关阅读:
    Linux下多线程查看工具(pstree、ps、pstack)
    linux的netstat命令详解
    linux的netstat命令详解
    实例解说Linux命令行uniq
    实例解说Linux命令行uniq
    实例解说Linux命令行uniq
    linux之sort用法
    linux之sort用法
    linux之sort用法
    oracle服务器和客户端字符集的查看和修改
  • 原文地址:https://www.cnblogs.com/BaseAI/p/13862340.html
Copyright © 2011-2022 走看看