zoukankan      html  css  js  c++  java
  • AGC002 补题小结

    Problem A Range Product

    简要题意:给定 (a,b) 两个数字,输出 (prod_{i=a}^b i) 是正数,负数还是零。 (-10^9 le ale ble 10^9)

    tag:分类讨论

    题解:分类讨论一下没了

    #include <cstdio>
    int main (){
        int a,b;scanf ("%d%d",&a,&b);
        if (a<=0&&b>=0) puts("Zero");
        else if (a<0&&b<0&&((b-a+1)&1)) puts("Negative");
        else puts("Positive");
        return 0;
    }
    

    Problem B Box and Ball

    简要题意:(N) 个盒子,第一个盒子里是个红球,其他 (N-1) 个盒子里都是白球。现在给出 (M) 次操作,操作的方式是在一个盒子中随机取出一个球放入另一个盒子中。在 (M) 次操作完后,求出红球可能在的盒子的总数。(N,M le 10^5)

    tag:枚举,按题意模拟

    题解:按题意模拟,记录每个盒子是否可能有球

    #include <cstdio>
    const int N=100005;
    bool vis[N];int cnt[N];
    int main (){
        int n,m;scanf ("%d%d",&n,&m);vis[1]=true;
        for (int i=1;i<=n;i++) cnt[i]=1;
        for (int i=1,x,y;i<=m;i++){
            scanf ("%d%d",&x,&y);
            vis[y]|=vis[x],cnt[x]--,cnt[y]++;
            if (cnt[x]==0) vis[x]=false;
        }
        int ans=0;for (int i=1;i<=n;i++) ans+=vis[i];
        printf ("%d",ans);
        return 0;
    }
    

    Problem C Knot Puzzle

    简要题意:有 (N) 条绳子,第 (i) 条的长度是 (A_i) 。 相邻两条绳子打了结,每次选一段绳子, 如果这段绳子的总长度大于给定的变量 (L) ,我们可以在这段绳子中选一个解开。问是否有一种方案把所有绳子都解开。 (N le 10^5)

    tag:贪心

    题解:考虑进行到只剩一个绳结,则两段绳子的长度和必须大于等于L,否则这个绳结没法解。所以找到整根绳子中长度和大于等于L的两段,将左边的绳结从左往右解开,右边的绳结从右往左解开,最后将这个绳结解开。

    #include <cstdio>
    const int N=100005;
    int a[N];
    int main (){
        int n,L;scanf ("%d%d",&n,&L);
        for (int i=1;i<=n;i++) scanf ("%d",&a[i]);
        for (int i=1;i<n;i++){
            if (a[i]+a[i+1]>=L) {
                puts("Possible");
                for (int j=1;j<i;j++)  printf ("%d
    ",j);
                for (int j=n-1;j>i;j--) printf ("%d
    ",j);
                printf ("%d",i);
                return 0;
            }
        }
        puts("Impossible");
        return 0;
    }
    

    Problem D Stamp Rally

    简要题意:一张连通图, (q) 次询问从两个点 (x)(y) 出发,希望经过的点(不重复)数量等于 (z) ,经过的边最大编号最小是多少。(n,q le 10^5)

    tag:整体二分,带撤销并查集

    题解:(Atcoder) 里罕见的数据结构题,对所有询问一起二分答案,用并查集判断是否可行,挺套路的一种题。

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int N=1e5+5;
    int ans[N];
    inline int Max(int a,int b){
    	return a>b?a:b;
    }
    struct Edge{
    	int u,v;
    }e[N];
    struct Node{int id,x,y,z;};
    int fa[N];
    inline int getrt(int x){while (fa[x]!=x)x=fa[x];return x;}
    int size[N],deep[N],s[N][2],top=0;
    bool tag[N];
    inline void link(int x,int y){
    	if (deep[x]<deep[y]) swap(x,y);
    	++top,s[top][0]=x,s[top][1]=y;
    	fa[y]=x,size[x]+=size[y];
    	if (deep[x]==deep[y]) deep[x]++,tag[top]=1;else tag[top]=0;
    }
    inline void pop(){
    	fa[s[top][1]]=s[top][1],size[s[top][0]]-=size[s[top][1]];
    	deep[s[top][0]]-=tag[top];tag[top]=0;--top;
    }
    inline void work(int l,int r,vector <Node > now){
    	if (now.size()==0) return;
    	if (l==r){
    		for (int i=0;i<now.size();i++) ans[now[i].id]=l;
    		return;
    	}
    	vector <Node > mx,mn;mx.clear(),mn.clear();
    	int mid=(l+r)>>1,nowtop=top;
    	for (int i=l,x,y;i<=mid;i++) if ((x=getrt(e[i].u))!=(y=getrt(e[i].v))) link(x,y);
    	for (int i=0;i<now.size();i++){
    		int x=getrt(now[i].x),y=getrt(now[i].y),sum=0;
    		if (x!=y) sum=size[x]+size[y];
    		else sum=size[x];
    		if (sum>=now[i].z) mn.push_back(now[i]);
    		else mx.push_back(now[i]);
    	}
    	work(mid+1,r,mx);
    	while (top>nowtop) pop();
    	work(l,mid,mn);
    }
    int main (){
    	int n,m,q;scanf ("%d%d",&n,&m);
    	for (int i=1;i<=m;i++)
    		scanf ("%d%d",&e[i].u,&e[i].v);
    	scanf ("%d",&q);
    	vector <Node > t;t.clear();
    	for (int i=1;i<=q;i++){
    		int x,y,z;scanf ("%d%d%d",&x,&y,&z);
    		t.push_back((Node){i,x,y,z});
    	}
    	for (int i=1;i<=n;i++) fa[i]=i,size[i]=deep[i]=1;
    	work(1,m,t);
    	for (int i=1;i<=q;i++) printf ("%d
    ",ans[i]);
    	return 0;
    }
    
    

    Problem E Candy Piles

    简要题意:桌子上有 (n) 堆糖,第 (i) 堆有 (a_i) 个,两个人轮流玩游戏,有两种操作:

    1. 把最多的一堆吃完
    2. 把每一堆吃掉一个

    吃完的人输,问两人足够聪明的博弈结果。 (nle 10^5,a_ile 10^9)

    tag:博弈,推结论

    题解:首先转化为平面上,按照 (a_i) 从大到小排序,两个人轮流走,可以向上或者向右走,走不了的人失败

    有个结论,((x,y)) 这个状态如果对于先手是必胜态,那么 ((x+1,y+1)) 也对于先手是必胜态,反之亦然

    所以我们可以直接找到 ((0,0)) 对应的是哪个点 ((i,i)) ,算出这个点到上方和右方轮廓的距离,只要有一个是偶数,就先手必胜。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N=100005;
    int a[N];
    bool cmp(int a,int b){return a>b;}
    int main (){
    	int n;scanf ("%d",&n);
    	for (int i=1;i<=n;i++) scanf ("%d",&a[i]);
    	sort(a+1,a+n+1,cmp);
    	for (int i=1;i<=n;i++)
    		if (i+1>a[i+1]){
    			int j=i+1;while (a[j]==i) j++;
    			if (((j-i-1)&1)|((a[i]-i)&1)) puts("First");
    			else puts("Second");
    			return 0;
    		}
    	return 0;
    }
    

    Problem F Leftmost Ball

    简要题意:给你 (n) 种颜色的球,每个球有 (k) 个,把这 (n imes k) 个球排成一排,把每一种颜色的最左边出现的球涂成白色(初始球不包含白色),求有多少种不同的颜色序列,答案对 (10^9+7) 取模 。(nle 2000)

    tag:计数类 (dp) ,组合数学

    题解:设 (f[i][j]) 表示填了 (i) 个白色球,(j) 彩色球的方案数,那么显然 (jle i)

    考虑这个转移,首先可以填一个白色,就是 (f[i][j]+=f[i-1][j])

    放新的颜色的球:即从 (f[i][j-1]) 转移,先在剩下 (n-j+1) 种没有放置过的颜色中选择一个作为这次放置的颜色,放置在第一个空位(按转移规则,已经放置的 (i) 个白球一定都在当前第一个空位的前面,因此必定合法)。放完后还剩 (k-2) 的这个颜色的球没有放,显然只需要在剩下的后面 (n imes k-i-(j-1) imes (k-1)-1) 个空位里找任意 (k-2) 个空位放就好,有 $ inom{n imes k−(i+(j−1) imes (k−1))}{k−2}$ 种方案

    所以总的转移方程是

    [f[i][j]=f[i-1][j]+f[i][j-1] imes (n-j+1) imes inom{n imes k−(i+(j−1) imes (k−1))}{k−2} ]

    注意特判 (k=1) 的情况

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int N=2005,Mod=1e9+7;
    int dp[N][N],fac[N*N],inv[N*N];
    inline int C(int n,int m){
    	return 1ll*fac[n]*inv[m]%Mod*inv[n-m]%Mod;
    }
    inline int qpow(int a,int b){
    	int ans=1;
    	while (b){
    		if (b&1) ans=1ll*ans*a%Mod;
    		a=1ll*a*a%Mod,b>>=1;
    	}
    	return ans;
    }
    int main (){
    	int n,k;scanf ("%d%d",&n,&k);
    	if (k==1) {puts("1");return 0;}
    	dp[0][0]=1;fac[0]=1;
    	for (int i=1;i<=n*k;i++) fac[i]=1ll*fac[i-1]*i%Mod;
    	inv[n*k]=qpow(fac[n*k],Mod-2);for (int i=n*k-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%Mod;
        for (int i=0;i<=n;i++) dp[i][0]=1;
    	for (int i=1;i<=n;i++)
            for (int j=0;j<=i;j++)
                dp[i][j]=dp[i-1][j]+1ll*dp[i][j-1]*(n-j+1)%Mod*C(n*k-(i+(j-1)*(k-1))-1,k-2)%Mod,dp[i][j]%=Mod;
        printf ("%d",dp[n][n]);
    	return 0;
    }
    
  • 相关阅读:
    CodeForces 659F Polycarp and Hay
    CodeForces 713C Sonya and Problem Wihtout a Legend
    CodeForces 712D Memory and Scores
    CodeForces 689E Mike and Geometry Problem
    CodeForces 675D Tree Construction
    CodeForces 671A Recycling Bottles
    CodeForces 667C Reberland Linguistics
    CodeForces 672D Robin Hood
    CodeForces 675E Trains and Statistic
    CodeForces 676D Theseus and labyrinth
  • 原文地址:https://www.cnblogs.com/crazyzh/p/10883753.html
Copyright © 2011-2022 走看看