• AtCoder Beginner Contest 214


    ( ext{E - Packing Under Range Regulations})

    解法

    将左端点从小到大排序,把对应的右端点插入优先队列。然后枚举盒子 (i) 放入当前优先队列第一个元素,删除后判断优先队列里第一个元素能否放入 (i+1) 之后的盒子。最后插入新的左端点对应右端点。

    这样保证可以放置的情况下,右端点顺序是递增的。

    代码

    #include <cstdio>
    #define print(x,y) write(x),putchar(y)
    
    template <class T>
    inline T read(const T sample) {
    	T x=0; char s; bool f=0;
    	while((s=getchar())>'9' or s<'0')
    		f|=(s=='-');
    	while(s>='0' and s<='9')
    		x=(x<<1)+(x<<3)+(s^48),
    		s=getchar();
    	return f?-x:x;
    }
    
    template <class T>
    inline void write(const T x) {
    	if(x<0) {
    		putchar('-'),write(-x);
    		return;
    	}
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    }
    
    #include <map>
    #include <queue>
    #include <vector>
    using namespace std;
    
    const int maxn=2e5+5;
    
    priority_queue < int,vector<int>,greater<int> > q;
    int n,idx;
    map <int,int> mp;
    vector <int> g[maxn];
    
    int main() {
    	int x,y;
    	for(int T=read(9);T;--T) {
    		n=read(9); mp.clear();
    		while(!q.empty()) q.pop();
    		idx=0;
    		for(int i=1;i<=n;++i) {
    			x=read(9),y=read(9);
    			if(!mp.count(x)) {
    				mp[x]=++idx;
    				g[idx].clear();
    			}
    			g[mp[x]].push_back(y);
    		}
    		mp[1e9+1]=1;
    		int i=mp.begin()->first;
    		bool ans=0;
    		while(i<=1e9) {
    			x=mp[i];
    			for(int j=0;j<g[x].size();++j)	
    				q.push(g[x][j]);
    			q.pop();
    			if(q.empty())
    				i=mp.lower_bound(i+1)->first;
    			else {
    				if(q.top()<=i) {
    					ans=1; break;
    				}
    				++i;
    			}
    		}
    		if(!q.empty()) ans=1;
    		puts(ans?"No":"Yes");
    	}
    	return 0;
    }
    

    ( ext{G - Three Permutations})

    解法

    前几天才做了夫妻围坐问题… 但是还是不会做。令人生草。关于夫妻围坐问题可以翻翻 "精尽人亡" 这场比赛,但是目前状态是咕咕咕。

    首先可以自然地联想到容斥原理,还是令 (A_i) 为 "满足 (i) 位置上是 (p_i)(q_i)" 的方案集合。如果将 ((p_i,q_i)) 连边最后生成一个环的话就是原问题,但实际上本题可能生成多个环。不过很好的一点是一个连通块也只能是环,因为每个点的入度与出度都是 (1)

    所以问题实际上可以分解为:对每个环求解 (sum_{1le i_1<i_2<...<i_kle n} |A_{i_1}cap A_{i_2}cap ...cap A_{i_k}|),然后 (mathcal O(n^2))(mathtt{dp}) 把答案拼起来。

    对于大小为 (cnt) 的环,我们发现第 (i) 条边与 (p_i) 的交界可以视作 (i) 位置上是 (p_i)(q_i) 同理。而且假设与 (p_i) 相邻的另一条边是 (j)(显然 (p_i=q_j)),那么 "满足 (i) 位置上是 (p_i)" 时,"满足 (i) 位置上是 (q_i)" 和 "满足 (j) 位置上是 (q_j)" 都是不可能成立的。转化到环上就是选取了第 (i) 条边与 (p_i) 的交界时,第 (i) 条边与 (q_i) 的交界和第 (j) 条边与 (q_j) 的交界都是不能选的。这就转化成了原问题。

    "交界" 有 (2cdot cnt) 个,假设选 (k) 个条件。套用公式可得方案数为 (inom{2cdot cnt-k-1}{k-1}cdot frac{2cdot cnt}{k}cdot (n-k)!)。如果懒得求 (k) 的逆元以及减去 (log) 的求逆元复杂度,可以转化成这个式子:(left ( inom{2cdot cnt-k}{k}+inom{2cdot cnt-k-1}{k-1} ight )cdot (n-k)!)

    自环需要特判一下。

    代码

    #include <cstdio>
    #define print(x,y) write(x),putchar(y)
    
    template <class T>
    inline T read(const T sample) {
    	T x=0; char s; bool f=0;
    	while((s=getchar())>'9' or s<'0')
    		f|=(s=='-');
    	while(s>='0' and s<='9')
    		x=(x<<1)+(x<<3)+(s^48),
    		s=getchar();
    	return f?-x:x;
    }
    
    template <class T>
    inline void write(const T x) {
    	if(x<0) {
    		putchar('-'),write(-x);
    		return;
    	}
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    }
    
    const int mod=1e9+7,maxn=3005;
    
    int n,a[maxn],b[maxn],to[maxn];
    int fac[maxn<<1],ifac[maxn<<1];
    int tmp[maxn],dp[maxn];
    bool vis[maxn];
    
    int inv(int x,int y=mod-2) {
    	int r=1;
    	while(y) {
    		if(y&1) r=1ll*r*x%mod;
    		x=1ll*x*x%mod; y>>=1;
    	}
    	return r;
    }
    
    void init() {
    	fac[0]=1;
    	for(int i=1;i<=(n<<1);++i)
    		fac[i]=1ll*fac[i-1]*i%mod;
    	ifac[n<<1]=inv(fac[n<<1]);
    	for(int i=(n<<1)-1;i>=0;--i)
    		ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
    }
    
    int C(int n,int m) {
    	if(n<m or n<0 or m<0)
    		return 0;
    	return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
    }
    
    signed main() {
    	n=read(9); init();
    	for(int i=1;i<=n;++i)
    		a[i]=read(9);
    	for(int i=1;i<=n;++i)
    		b[i]=read(9),
    		to[a[i]]=b[i];
    	dp[0]=1;
    	for(int i=1;i<=n;++i) {
    		if(vis[i]) continue;
    		int cnt=0;
    		for(int j=i;!vis[j];j=to[j]) {
    			++cnt;
    			vis[j]=1;
    		}
    		for(int j=0;j<=n;++j)
    			tmp[j]=0;
    		for(int j=0;j<=cnt;++j) {
    			int inc=(C(cnt*2-j,j)+C(cnt*2-j-1,j-1))%mod;
    			if(cnt==1 and j==1) inc=1;
    			for(int k=0;k<=n-j;++k)
    				tmp[j+k]=(tmp[j+k]+1ll*dp[k]*inc%mod)%mod;
    		}
    		for(int j=0;j<=n;++j)
    			dp[j]=tmp[j];
    	}
    	int ans=0;
    	for(int i=0;i<=n;++i) {
    		int t=1ll*fac[n-i]*dp[i]%mod;
    		if(i&1) ans=(ans-t+mod)%mod;
    		else ans=(ans+t)%mod;
    	}
    	print(ans,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    E小press框架之第三步(参数接收)
    Express框架之第二步(路由)
    Express框架之第一步(创建工程)
    【排序】基数排序
    【数学】平方和公式$$sum_{i=1}^{n}i^2=frac{n(n+1)(2n+1)}{6}$$
    【博弈论】Nim游戏
    【搜索】对抗搜索【CF】J. Situation
    【图论】Kruskal算法
    dijkstra算法+堆优化 + 链式前向星版本
    【DP】【数位DP】
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/15158975.html
Copyright © 2020-2023  润新知