noip模拟18

A 图 (a)

好像很简单,但是想了很久。

考虑一条边,最终能保留下来的条件,就是被操作了奇数次。又由于 \(m\) 最大只有 \(64\),正好能用一个 ull 存下来,第 \(i\) 位表示第 \(i\) 次操作,是否属于 \(S\)\(T\) 集合。

然后枚举每一条边,若边 \((x,y)\) 的两节点分别在 \(S\)\(T\) 中出现了奇数次,那么这条边是可取的。统计即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
const int N=1e4+4;
int n,m;
int s[N],t[N];

signed main()
{
//	freopen("in.in","r",stdin);
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout); 
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		string c;cin>>c;
		for(int j=0;j<n;j++)
		{
//			int now=c[j]
			if(c[j]=='1'||c[j]=='3') s[j+1]|=(1ull<<i);
			if(c[j]=='2'||c[j]=='3') t[j+1]|=(1ull<<i);
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
		ans+=(__builtin_popcountll((s[i]&t[j])|(s[j]&t[i]))%2);
	cout<<ans;
}

B 序列 (b)

发现一个判断贪心题的好方法:如果题目要求最大值后取模,并且最大值可能极大,那基本上选取策略就是固定的了。不会有答案结果大小的优劣抉择。

这道题就是这样。我们把对于同一个数的所有修改操作只留下一个最优的,其他舍弃。假设剩下的参数为 \(y\),再把这个操作等价成给 \(a_i\) 加上 \(y-a_i\)。这样就只留下两种操作了。

考虑给 \(a_i\) 加上一个数,等于乘以 \(\frac{a_i+y}{a_i}\),这样就只剩下一种操作了。

乘法操作就从大往小取就行了,先乘大的数肯定更好。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
const int N=1e5+5;
int a[N];
int ans[N];
struct node{
	int op,x,y;
}b[N];
int now[N];
const int mod=1e9+7;
int ad[N];
vector<int>e[N];
priority_queue<pair<double,int> >q;
int ppow(int a,int b)
{
	int res=1;
	while(b)
	{
		if(b&1) res=(res*a)%mod;
		a=(a*a)%mod,b>>=1;
	}return res;
}
signed main()
{
	freopen("b.in","r",stdin);
	freopen("b.out","w",stdout); 
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=m;i++)cin>>b[i].op>>b[i].x>>b[i].y;
	int qq=0;
	for(int i=1;i<=m;i++)
	{
		if(b[i].op==1) 
		{
//			if(b[i].y-a[b[i].x]<ad[b[i].x])++q;
			ad[b[i].x]=max(ad[b[i].x],b[i].y-a[b[i].x]);
		
		}if(b[i].op==2) e[b[i].x].push_back(b[i].y);
		if(b[i].op==3) q.push({b[i].y,-b[i].y});
	}
	
	int ans=1;
	for(int i=1;i<=n;i++)
	{
		if(ad[i]) e[i].push_back(ad[i]);
		ans=(ans*a[i])%mod;
	}
	for(int i=1;i<=n;i++)
	{
//		cout<<e[i].size()<<" ";
		if(!e[i].size()) continue;
		sort(e[i].begin(),e[i].end());
		q.push({1.0*(e[i].back()+a[i])/(1.0*a[i]),i});
//		e[i].pop_back();
	}
//	cout<<"dic\n";
	cout<<ans<<" ";
	while(!q.empty())
	{
		++qq;
		int now=q.top().second;q.pop();
		if(now<0)
		{
			now=-now;
			ans=(ans*now)%mod;
		}
		else
		{
			ans=ans*(a[now]+e[now].back())%mod*ppow(a[now],mod-2)%mod;
			a[now]+=e[now].back(),e[now].pop_back();
			if(e[now].size())
			q.push({1.0*(e[now].back()+a[now])/(1.0*a[now]),now});
		}
		cout<<ans<<" ";
	}
	for(int i=qq+1;i<=m;i++) cout<<ans<<" ";
}

C 树 (c)

先手非常能赢,输出 \(n^{2D}\) 可获得 \(90\) 分。加上 \(D=1\)\(O(n)\) dp:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
int u,v,now,f[N],g,fa[N],dep[N],cnt[2];
const int mod=1e9+7;
bool fg[N],dp[N],wd[N],tag[N];
long long b,ans,num;
vector<int>e[N];
void dfs(int u)
{
	cnt[dep[u]]++;
	for(int v:e[u])
	{
		if(v!=fa[u])
		{
			dep[v]=dep[u]^1;
			fa[v]=u,dfs(v);
			if(!fg[v])fg[u]=1;
		}
	}
}
int ppow(int a,int b)
{
	int res=1;
	while(b)
	{
		if(b&1) res=(res*a)%mod;
		a=(a*a)%mod,b>>=1;
	}return res;
}
int check(int u)
{
	int res=0;
	for(int v:e[u])
	{
		if(v!=fa[u]&&!fg[v])res++;
	}
	if(fa[u])res+=(!dp[fa[u]]);
	return res;
}
int check0(int u)
{
	int res=0;
	for(int v:e[u])
	{
		if(v!=fa[u]&&!fg[v])res++;
	}
	return res;
}
void dfsp(int u)
{
	int res=check(u);
	for(int v:e[u])
	{
		if(v!=fa[u])
		{
			fa[v]=u;
			if(fg[v])dp[v]=1;
			else dp[v]=(res==1);
			dfsp(v);
		}
	}
}
void dfs0(int u)
{
	tag[u]=1;
	if(!fg[u])	num++;
	for(int v:e[u])
	{
		if(v!=fa[u])
		{
			if(fg[u])
			{
				if(!fg[v])dfs0(v);
			}
			else if(fg[v]&&wd[v])dfs0(v);
		}
	}
}
signed main()
{
//	freopen("c0.in","r",stdin);
//	freopen("c.out","w",stdout);
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	int n,m;cin>>n>>m;
	for(int i=1;i<n;i++)
	{
		cin>>u>>v,e[u].push_back(v),e[v].push_back(u);
	}
	if(m>1){
		return cout<<ppow(n,2*m),0;
	}
	dfs(1),dp[1]=fg[1],dfsp(1);
	for(int i=1;i<=n;i++)
	{
		if(fg[i]&&check0(i)==1)	wd[i]=1;
	}
	if(!fg[1]||wd[1])dfs0(1);
	if(!fg[1])
	{
		for(int i=1;i<=n;i++)	if(!dp[i])ans=(ans+num)%mod;
	}
	else
	{
		ans=(1LL*n*n)%mod;
		for(int i=1;i<=n;i++)
			if(!dp[i])ans=(ans-num+mod)%mod;
	}
	cout<<ans;
	return 0;
}

D 字符串 (d)

posted @ 2024-11-21 22:00  ccjjxx  阅读(8)  评论(0编辑  收藏  举报