• 2018ICPC南京网络赛


    2018ICPC南京网络赛

    A. An Olympian Math Problem

    题目描述:求(sum_{i=1}^{n} i imes i! \%n)

    solution

    [(n-1) imes (n-1)! \% n= (n-2)!(n^2-2n+1) \%n =(n-2)! ]

    [(n-2+1) imes (n-2)! \% n= (n-3)!(n^2-3n+2) \%n =(n-3)! imes 2 ]

    以此类推,最终只剩下(n-1)

    时间复杂度:(O(1))

    B. The writing on the wall

    题目描述:有一个(n imes m)的网格图,其中有些格子是黑色,其它都是白色,问不含黑色格子的矩形有多少个。

    solution
    先预处理出每个格子向右延伸的最长距离是多少,记作(ri[i][j])
    对于每一列(j),将行按(ri)从大到小排序,按顺序插回去,用并查集维护连通块,当将第(i)行插回去是,(i)所在的连通块最长延伸距离为(ri[i][j]),为避免重复,只算跨过(i)这一行的贡献。

    时间复杂度:(O(n^3))

    C. GDY

    据说是比较坑的模拟题,队友做的。

    D. Jerome's House

    题目描述:在一个凸包内放三个半径为(r)的圆(圆可以相交),求圆心所形成的三角形的面积的最大值的两倍。

    solution
    将凸包的所有边向内移动(r),用半平面交求出之后的凸包,然后在凸包上求面积最大的三角形,枚举两个点,然后第三个点是单调的。

    时间复杂度:(O(n^2))

    E. AC Challenge

    裸状压(dp).

    F. An Easy Problem On The Trees

    G. Lpl and Energy-saving Lamps

    裸线段树。

    H. Set

    题目描述:有(n)个点, 每个点有一个权值。(m)个操作,操作有三种:

    1. 给定(u, v),如果(u, v)不在同一个集合,那么将它们所在的集合合并
    2. 给定(u),将(u)所在集合的点的权值加一。
    3. 给定(u, k, x),求(u)所在集合的点的权值模(2^k)等于(x)的有多少。

    solution
    看到第三个操作,就会想到用(trie)来维护每个集合的数(越接近树根数位越低),操作一就是将两棵(trie)暴力合并,由于只有合并操作,因此每个点只会被合并一次,因此总的时间复杂度还是(O(nlogn)),对于操作二,可以在(trie)上面打标记,表示子树要加数,假设加的数为(x),若(x)为奇数,则本来该数位是(0)的数变成(1)(1)变成(0),并且要进位,即交换儿子,交换后儿子(0)的标记加一;若(x)为偶数,则直接把标记往下打即可,往下打得标记为(x/2).

    时间复杂度:(O((n+m)k))

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn=int(6e5)+100;
    
    struct node
    {
    	node *son[2];
    	int cnt;
    	int mark;
    
    	node()
    	{
    		cnt=mark=0;
    		son[0]=son[1]=NULL;
    	}
    
    	void down()
    	{
    		if (mark & 1) swap(son[0], son[1]);
    		if (son[0]) son[0]->mark+=(mark>>1)+(mark & 1);
    		if (son[1]) son[1]->mark+=(mark>>1);
    		mark=0;
    	}
    };
    
    node memory[maxn*31];
    node *mem=memory;
    int n, m;
    int dsu[maxn];
    node *trie[maxn];
    
    void insert(node *cur, int v)
    {
    	++cur->cnt;
    	for (int i=0; i<30; ++i, v>>=1)
    	{
    		if (!cur->son[v & 1]) cur->son[v & 1]=mem++;
    		cur=cur->son[v & 1];
    		++cur->cnt;
    	}
    }
    void read()
    {
    	scanf("%d%d", &n, &m);
    	for (int i=1; i<=n; ++i) dsu[i]=-1;
    	for (int i=1; i<=n; ++i)
    	{
    		int v;
    		scanf("%d", &v);
    		trie[i]=mem++;
    		insert(trie[i], v);
    	}
    }
    int dsu_find(int cur)
    {
    	return (dsu[cur]<0? cur:(dsu[cur]=dsu_find(dsu[cur])));
    }
    void dsu_merge(int &x, int &y)
    {
    	if (dsu[x]>dsu[y]) swap(x, y);
    	dsu[x]+=dsu[y];
    	dsu[y]=x;
    }
    node *merge(node *x, node *y)
    {
    	if (!x) return y;
    	if (!y) return x;
    	if (x->mark) x->down();
    	if (y->mark) y->down();
    	x->cnt+=y->cnt;
    	x->son[0]=merge(x->son[0], y->son[0]);
    	x->son[1]=merge(x->son[1], y->son[1]);
    	return x;
    }
    int ask(node *cur, int k, int x)
    {
    	if (cur->mark) cur->down();
    	for (int i=0; i<k; ++i, x>>=1)
    	{
    		if (!cur->son[x & 1]) return 0;
    		cur=cur->son[x & 1];
    		if (cur->mark) cur->down();
    	}
    	return cur->cnt;
    }
    void solve()
    {
    	for (int i=1; i<=m; ++i)
    	{
    		int type, u, v, x;
    		scanf("%d%d", &type, &u);
    		u=dsu_find(u);
    		switch (type)
    		{
    			case 1:
    				scanf("%d", &v);
    				v=dsu_find(v);
    				if (u==v) break;
    				dsu_merge(u, v);
    				trie[u]=merge(trie[u], trie[v]);
    				break;
    			case 2:
    				++trie[u]->mark;
    				break;
    			case 3:
    				scanf("%d%d", &v, &x);
    				printf("%d
    ", ask(trie[u], v, x));
    				break;
    		}
    	}
    }
    int main()
    {
    	read();
    	solve();
    	return 0;
    }
    

    I. Skr

    题目描述:给定一个只含数字的字符串,求不同回文子串的和(子串所代表的数字的和)

    solution
    裸回文树。

    J. Sum

    题目描述:定义(f(n))(n)分解为两个非平方数乘积的方案数(有序数对),非平方数指的是没有平方数因子的数,(1)除外。问(sum_{i=1}^{n} f(i))

    solution
    将一个数(n)分解质因数,若某个质因子的幂大于(2),则(f(n)=0),因为无论怎么分,总有一个数会有两个该质因子;否则(f(n)=2^{幂次为1的质因子的个数})。而这东西显然是积性函数,因此可以线性筛预处理。

    时间复杂度:(O(n))

    K. The Great Nim Game

    题目描述:有(n)堆石子,每堆石子的个数为(f(n)),一开始可以移走若干堆石子,使得在剩下的石子堆中玩(Nim)游戏先手必胜,问移走石子堆的方案数。

    solution
    如果直接给出每堆石子的个数,那这题就很简单了,就是算使得剩下的数异或值不为(0)即可,这个可以用状压(dp)。但这道题的(n)很大,(f(n))是由递推式给出的。观察式子可知(f(n))有一个长度为(k)的循环,因此可以算出每种数字有多少个,只是要用高精度表示而已,每种数字选奇数个或偶数个,因此方案数是(2^{个数-1}),因为个数很大,所以要用欧拉定理降幂。

    时间复杂度:(O(n+2^kk))

    L. Magical Girl Haze

    题目描述:有一个(n)个点(m)条边的图,现在可以将不多于(k)条边的权值变成(0),求(1)(n)的最短路径。

    solution
    拆点,将一个点拆成(k+1)个,表示已经变了多少条边。然后用(dijkstra)才能过。(好像(SPFA+SLF)优化也可以)

    时间复杂度:(O(mlog(nk)))

  • 相关阅读:
    MySQL数据库生成某一年的日历存储过程
    MySQL随笔(四)
    MySQL索引
    MySQL随笔(三)
    MySQL随笔(二)
    MySQL随笔(一)
    设计模式---策略模式
    数组间相互转换 int[]转list
    安装brew -- Homebrew
    mongodb查询方法
  • 原文地址:https://www.cnblogs.com/GerynOhenz/p/9595316.html
Copyright © 2020-2023  润新知