zoukankan      html  css  js  c++  java
  • hgoi#20191101

    T1-awesome

    给定一个可重集合和一个质数 $ P $ ,求本质不同的乘积模 $ P $ 为 $ 1 $ 的三元组的数目。

    解法

    暴力分三种情况讨论
    三个不同的数,两个不同的数,一个数
    三个不同的数,先两两求出模 $ P $ 意义下的乘积
    然后对于每个数询问其逆元
    两个不同的数,一个数,这两种情况直接暴力枚举即可

    ac代码

    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #include<bits/stdc++.h>
    using namespace std; 
    unordered_map<int,int>mp;
    int n,P,cnt,x,ans,a[2500],s[2500],ni[2500],g[2500];
    int p(int a,int b)
    {
    	int ret=1;
    	while(b)
    	{
    		if(b&1)ret=1ll*ret*a%P;
    		a=1ll*a*a%P,b/=2;
    	}
    	return ret;
    }
    int main()
    {
    	freopen("awesome.in","r",stdin);
    	freopen("awesome.out","w",stdout);
    	scanf("%d%d",&n,&P);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&x);
    		if(!mp[x])
    			a[++cnt]=x%P,ni[cnt]=p(x%P,P-2),mp[x]=cnt;
    		s[mp[x]]++;
    	}
    	mp.clear();
    	// 1 1 1
    	for(int i=1;i<=cnt;i++)
    		for(int j=1;j<=cnt;j++)
    			if(i!=j)
    			{
    				int mo=1ll*a[i]*a[j]%P;
    				mp[mo]++;
    				if(mo==ni[i])g[i]++;
    				if(mo==ni[j])g[j]++;
    			}
    	for(int i=1;i<=cnt;i++)
    		if(mp.count(ni[i]))ans+=mp[ni[i]]-g[i];
    	ans/=6;
    	// 1 2
    	for(int i=1;i<=cnt;i++)
    		for(int j=1;j<=cnt;j++)
    			if(i!=j&&s[j]>1)
    				if(1ll*a[i]*a[j]%P*a[j]%P==1)
    					ans++;
    	// 3
    	for(int i=1;i<=cnt;i++)
    		if(s[i]>2)
    			if(1ll*a[i]*a[i]%P*a[i]%P==1)
    				ans++;
    	printf("%d
    ",ans);
    	return 0;
    }
    

    T2-bag

    二维平面上给定 $ n $ 个点,并给额外 $ m $ 个背包,每个背包有一个容量。
    求一个二维偏序下最长链,满足可以给每个链上的点分配一个背包,使得每个点的 $ x $ 值都不超过其对应的背包容量。

    解法

    对于容量,可以直接排序使其递减
    那么设 $ f_i $ 表示链的长度为 $ i $ 时最小的 $ y $ 值
    就是一个带限制的最长不上升子序列
    $ x $ 值大的点一定优先塞到容量大的背包内
    之后就和最长不上升子序列一样做即可

    ac代码

    #include<bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define mid (l+r>>1)
    using namespace std;
    struct node
    {
    	int w,v;
    	void init(){scanf("%d%d",&w,&v);}
    	bool operator<(const node&a)const{return w==a.w?v>a.v:w>a.w;}
    }a[100010];
    int T,n,m,cnt,ans,l,r,ret,t[100010],p[200010],f[100010];
    int cmp(int a,int b){return a>b;}
    int id(int x){return lower_bound(p+1,p+cnt+1,x)-p;}
    int main()
    {
    	scanf("%d",&T);
    	while(T--)
    	{
    		memset(f,0,sizeof(f)),f[0]=inf,ans=cnt=0;
    		scanf("%d",&n);
    		for(int i=1;i<=n;i++)a[i].init(),p[++cnt]=a[i].w;
    		scanf("%d",&m);
    		for(int i=1;i<=m;i++)scanf("%d",&t[i]),p[++cnt]=t[i];
    		sort(a+1,a+n+1),sort(t+1,t+m+1,cmp),sort(p+1,p+cnt+1);
    		cnt=unique(p+1,p+cnt+1)-p-1;
    		for(int i=1;i<=n;i++)a[i].w=id(a[i].w);
    		for(int i=1;i<=m;i++)t[i]=id(t[i]);
    		for(int i=1;i<=n;i++)
    		{
    			l=1,r=m,ret=-1;
    			while(l<=r)
    				if(t[mid]>=a[i].w)ret=mid,l=mid+1;
    				else r=mid-1;
    			if(ret==-1)continue;
    			l=0,r=ret-1,ret=-1;
    			while(l<=r)
    				if(f[mid]>=a[i].v)ret=mid,l=mid+1;
    				else r=mid-1;
    			ans=max(ans,ret+1),f[ret+1]=max(f[ret+1],a[i].v);
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

    T3-subtree

    合法的有根树满足下列条件:每个点的父亲编号比自己小且所有子树大小不与任一规定的禁止值相等
    求 $ n $ 个节点深度为 $ j $ 的合法有根树数目模 $ 998244353 $ ,其中 $ L leq j leq R $ 。

    解法

    设 $ dp_{i,d} $ 表示 $ i $ 个节点深度不超过 $ d $ 的方案数
    如果没有子树大小的限制,转移如下:
    $ dp_{i,d}= sumlimits_{j=1}^{i-1} dp_{i-j,d}×dp_{j,d-1}×C_{i-2}^{j-1} $
    对于限制,只要转移的时候把 $ dp_{j,d-1} $ 看成 $ 0 $ 即可

    ac代码

    #include<bits/stdc++.h>
    #define mod 998244353 
    using namespace std;
    int n,k,l,r,x,a[510],C[510][510],dp[510][510];
    int main()
    {
    	scanf("%d%d",&n,&k);
    	for(int i=0;i<=n;i++)
    	{
    		C[i][0]=1;
    		for(int j=1;j<=i;j++)
    			C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    	}
    	for(int i=1;i<=k;i++)
    		scanf("%d",&x),a[x]=1;
    	dp[1][1]=!a[1];
    	for(int d=2;d<=n;d++)
    	{
    		dp[1][d]=1;
    		for(int i=2;i<=n;i++)
    		{
    			for(int j=1;j<i;j++)
    				dp[i][d]=(dp[i][d]+1ll*dp[i-j][d]*dp[j][d-1]%mod*C[i-2][j-1])%mod;
    		}
    		for(int i=1;i<=n;i++)
    			if(a[i])dp[i][d]=0;
    	}
    	scanf("%d%d",&l,&r);
    	for(int i=l;i<=r;i++)
    		printf("%d ",(dp[n][i]-dp[n][i-1]+mod)%mod);
        return 0;
    }
    
  • 相关阅读:
    GridControl中属性
    Linux命令发送Http GET/POST请求
    centos 7.6 安装jdk8
    centos 基本操作 快捷键开户终端,复制,粘贴
    mybatis中转义 大于,小于,大于等于,小于等于,
    excel生成mybatis模板
    Linux下Tomcat重新启动
    Oracle 数据库裸设备扩容处理
    百度地图一套JS API,非常实用
    百度地图,标记,显示和隐藏的方法
  • 原文地址:https://www.cnblogs.com/muronglin/p/hgoi-20191101.html
Copyright © 2011-2022 走看看