• NOI ONLINE部分题解


    S-2涂色问题

    CF1260C —— 双倍经验

    一眼瞪出结论(当然细节挂了)

    就比较(k)(frac {p_2-2}{p_1} +1)的大小

    (k=0)的时候显然是“NO” ——我忘了

    而且可能不互质,所以要搞个gcd ——模了几个样例才想起来

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    const int N=1000005;
    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*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int p1,p2,k;
    int gcd(int a,int b) {
    	return b?gcd(b,a%b):a;
    }
    int main() {
    	// freopen("color.in","r",stdin);
    	// freopen("color.out","w",stdout);
    	int T=read();
    	while(T--) {
    		p1=read();p2=read();k=read();
    		if(p1>p2) swap(p1,p2);
    		int g=gcd(p1,p2);
    		p1/=g;p2/=g;
    		int ans=p2%p1,res;
    		if(ans==0) res=p2/p1-1;
    		else if(ans==1) res=p2/p1;
    		else res=p2/p1+1;
    		if(k==1) puts("NO");
    		else if(k>res) puts("YES");
    		else puts("NO");
    	}
    	return 0;
    }
    
    
    

    S-2 子序列问题

    复述一下题解

    https://www.luogu.com.cn/blog/duyi/solution-p6477

    首先看到 (a[i])的范围,离散化

    朴素是枚举左右端点,再用set维护集合元素个数,瓶颈在于枚举端点。

    正解是考虑每个(a[i])的贡献区间,设(a[i])上次出现的位置为(pre[i]),那么贡献区间即为 ([ (pre[i],i] , [i,n] ])

    接下来考虑平方的问题 ————经典套路

    平方看成在这些位置中,任选出两个位置(可以重复)的方案数!

    设它们分别为((i,j))(不妨设((ileq j)))。则一对((i,j))会对多少个区间产生贡献?不难发现,数量是:

    ((i-max( ext{pre}[i], ext{pre}[j]))cdot (n-j+1)quad (i> ext{pre}[j]))

    暴力枚举 ((i,j))复杂度是(O(n^2))的。考虑优化

    如何快速求出:(sum_{i=1}^{j}max( ext{pre}[i], ext{pre}[j]))。我们用一个变量,记录(j)前面所有( ext{pre}[i])之和,则只需要把(leq ext{pre})的这部分值减去,再加上相同数量的( ext{pre}[j])即可。可以用两个树状数组,都以( ext{pre})值为下标,分别维护( ext{pre})值小于(x)( ext{pre})值之和,及其数量。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N=1000005;
    const int P=1e9+7;
    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*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    
    ll s[N],num[N];//树状数组
    int n,a[N],b[N],mp[N],pre[N];
    inline void upd(int x,int v) {for(int i=x;i<=n;i+=i&-i)s[i]+=x*v,num[i]+=v;}
    inline ll sum(int x){ll res=0;for(int i=x;i;i-=i&-i)res+=num[i]*(x+1)-s[i];return res;}
    
    int main() {
    	n=read();
    	for(int i=1;i<=n;i++) a[i]=b[i]=read();
    	sort(b+1,b+1+n);
    	int tot=unique(b+1,b+1+n)-b-1;
    	for(int i=1;i<=n;i++) {
    		a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
    		pre[i]=mp[a[i]];
    		mp[a[i]]=i;
    	}
    	ll cnt=0,ans=0;
    	for(int i=1;i<=n;i++) {
    		cnt=(cnt+i-pre[i]+2*(sum(i)-sum(pre[i]))%P+P)%P;
    		ans=(ans+cnt)%P;
    		upd(pre[i]+1,1);upd(i+1,-1);
    	}
    	printf("%lld
    ",(ans%P+P)%P);
    	return 0;
    }
    

    J-2 建设城市

    组合数学

    组合弱者——推+写 近1小时

    分类讨论

    1. (x,y)同侧
      ([x,y])看成一个球 ,就是n-(y-x) 个球放到m个盒子里 (可以空)
      剩余 n 个球,放到m个盒子里 (可以空)

    2. 异侧

    剩余 n-x个球,放到m-i+1个盒子里(可以空)
    剩余 y-1个球,放到m-i+1个盒子里(可以空)
    剩余 n-y个球,放到i个盒子里(可以空)

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N=200005;
    const int P=998244353;
    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*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int m,n,x,y;
    ll fac[N],inv[N];
    ll qpow(ll a,ll b) {
    	ll res=1;
    	while(b) {
    		if(b&1) res=res*a%P;
    		a=a*a%P;
    		b>>=1;
    	}
    	return res;
    }
    inline ll C(int n,int m) {
    	if(n<0||n<m||m<0) return 1;
    	return fac[n]*inv[m]%P*inv[n-m]%P;
    }
    ll ans;
    int main() {
    	m=read();n=read();x=read();y=read();
    	fac[0]=1;
    	for(int i=1;i<=n+m;i++) 
    		fac[i]=fac[i-1]*i%P;
    	inv[n+m]=qpow(fac[n+m],P-2);
    	for(int i=n+m;i;i--) inv[i-1]=inv[i]*i%P;
    	if(x>y) swap(x,y);
    	if(x<=n&&y>n) {//异侧
    		y-=n;
    		for(int i=1;i<=m;i++) 
    			ans=(ans+C(x-2+i,i-1)*C(n-x+m-i,m-i)%P*C(y-1+m-i,m-i)%P*C(n-y+i-1,i-1)%P)%P;
    		printf("%lld
    ",ans);
    	}
    	else { //同侧
    		ans=C(n-(y-x)+m-1,m-1)*C(n+m-1,m-1)%P%P;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    LightOJ 1422 Halloween Costumes(区间dp)
    zoj 3537 Cake(区间dp)
    POJ 2955 Brackets(区间dp)
    HDU 1058 Humble Numbers(dp)
    uva 10934 Dropping water balloons(转载)
    树形dp
    Manacher算法求回文半径
    poj-1236.network of schools(强连通分量 + 图的入度出度)
    hdu-2255.奔小康赚大钱(最大权二分匹配)
    poj-2289.jamies contact groups(二分答案 + 二分多重匹配)
  • 原文地址:https://www.cnblogs.com/ke-xin/p/14102391.html
Copyright © 2020-2023  润新知