牛客周赛77(CDEF)

 小红走网格

不会的可以去看看裴蜀定理,经常用到,见过就会了

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const long long N=1e6+10,mod=998244353,INF=1e15;
ll n,m,k,a,b,c,d;
bool st[N];
void solve()
{
	cin>>n>>m>>a>>b>>c>>d;
	int x=__gcd(a,b),y=__gcd(c,d);
	if(m%x==0&&n%y==0)cout<<"YES"<<endl;
	else cout<<"NO"<<endl;
}
signed main()
{
    cin.tie(0), cout.tie(0), ios::sync_with_stdio(false);
    int T;cin>>T;
    while(T--)solve();
    return 0;
}

社交隐匿网格

按每一位考虑,假设当前考虑第i位,将所有在第i位上不为0的数用带权并查集合并就好了

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const long long N=1e6+10,mod=998244353,INF=1e15;
ll n,m,k,a[N],f[N],s[N];
bool st[N];
int find(int x)
{
	if(x!=f[x])f[x]=find(f[x]);
	return f[x];
}
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)f[i]=i,s[i]=1;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int j=0;j<=60;j++)
	{
		int lst=-1;
		for(int i=1;i<=n;i++)
		{
			if(a[i]>>j&1)
			{
				if(lst!=-1)
				{
					int fa=find(lst),fb=find(i);
					if(fa==fb)continue;
					s[fa]+=s[fb];
					f[fb]=fa;
				}
				lst=i;
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)ans=max(ans,s[find(i)]);
	cout<<ans<<endl;
}
signed main()
{
    cin.tie(0), cout.tie(0), ios::sync_with_stdio(false);
    int T;cin>>T;
    while(T--)solve();
    return 0;
}

1or0

线段树简单题,线段树里面维护答案,还有ll(区间左端有多少个连续的0),rr(区间右端有几个连续的0),具体怎么合并看代码,学过线段树就非常好懂

#include<bits/stdc++.h>
#define int long long
using namespace std;
const long long N=2e5+10;
int n,m;
string s;
struct node
{
	int l,r,ans,ll,rr;
}t[4*N];
void pushup(node &u,node L,node R)
{
	int lenl=L.r-L.l+1,lenr=R.r-R.l+1;
	u.l=L.l,u.r=R.r;
	u.ans=L.ans+R.ans+lenl*lenr-L.rr*R.ll;
	u.ll=L.ll+R.ll*(L.ll==lenl);
	u.rr=R.rr+L.rr*(R.rr==lenr);
}
void build(int u,int l,int r)
{
	t[u]={l,r};
	if(l==r)
	{
		int x=(s[l]=='1');
		t[u]={l,r,x,1-x,1-x};return;
	}
	int mid=(l+r)/2;
	build(u<<1,l,mid),build(u<<1|1,mid+1,r);
	pushup(t[u],t[u<<1],t[u<<1|1]);
}
node query(int u,int l,int r)
{
	if(l<=t[u].l&&t[u].r<=r)return t[u];
	else{
		int mid=(t[u].l+t[u].r)/2;
		if(r<=mid)return query(u<<1,l,r);
		if(l>mid)return query(u<<1|1,l,r);
		node ll,rr,res;
		ll=query(u<<1,l,r);
		rr=query(u<<1|1,l,r);
		pushup(res,ll,rr);
		return res;
	}
}
signed main()
{
	cin>>n;
	cin>>s;
	s=" "+s;
	cin>>m;
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		int l,r;cin>>l>>r;
		node res=query(1,l,r);
		cout<<res.ans<<endl;
	}
    return 0;
}

计数

考虑节点u,首先看它自己是不是关键节点,如果是那么cnt[u]初值为1,否则为0,因为他可以选自己,记dp[u]为子树u里面有多少个关键节点,那么cnt[u],还要加上他的所以儿子v的dp[v]两两相乘,这个也非常好算,直接边算dp边计数就可以了,cnt[u]+=2*dp[u]*dp[v],dp[u]+=dp[v],表示当前儿子于前面遍历到的所有节点的方案,再把这个儿子加到u里面,记得乘个2,这样可以保证不重不漏

#include<bits/stdc++.h>
#define int long long
using namespace std;
const long long N=1e5+10;
int n,m,k,a[N],cnt[N],dp[N];
vector<int>p[N];
void dfs(int u,int fa)
{
	cnt[u]=dp[u];
	for(int x:p[u])
	{
		if(x==fa)continue;
		dfs(x,u);
		cnt[u]+=2*dp[u]*dp[x];
		dp[u]+=dp[x];
	}
}
signed main()
{
	cin>>n;
	for(int i=1;i<n;i++)
	{
		int u,v;cin>>u>>v;
		p[u].push_back(v);
		p[v].push_back(u);
	}
	cin>>m;
	for(int i=1;i<=m;i++)
	{
		int x;cin>>x;
		dp[x]=1;
	}
	dfs(1,0);
	for(int i=1;i<=n;i++)cout<<cnt[i]<<' ';
	return 0;
}

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值