CCPC-Wannafly Winter Camp Day7 Div2

今天外婆生日,比赛没打完,只有3个题就滚粗了。

A.迷宫

这句话的意思是一个节点不能同时存在两个人

我们这样分析一下,是不是最终所有点都要到1节点,那我们只要求出所有人到1号点的距离d[i],排个序,假设ans为所有人全部逃跑花费的时间(初始0),遍历到第 i 个点,如果d[ i ]>ans,那么就更新ans=d[ i ],如果d[ i ]<=ans,是不是这个人要排队?此时更新ans=ans+1

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
vector<int>G[maxn];
int a[maxn],d[maxn],cnt,ans;
int dfs(int u,int fa,int deep)
{
	if(a[u])d[++cnt]=deep;
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(v==fa)continue;
		dfs(v,u,deep+1);
	}
}
int main()
{
	int n,u,v;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i]);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs(1,0,0);
	sort(d+1,d+1+cnt);
	for(int i=1;i<=cnt;i++)
	if(d[i]>ans)ans=d[i];
	else ans++;
	cout<<ans;
}

E.线性探查法

假设a[ 2 ]%7=5,a[ 2 ]本应该在第5个位置,但是却排到了第 2 位,说明已经有的数先抢占了5 6 0 1这些位置,那么连四条有向边到 2 即可,我们通过这种方式建有向图进行拓扑排序,不过普通队列换成权值小的数优先的优先队列就好了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=100005;
int n,d[maxn];
ll a[maxn],b[maxn];
vector<int>G[maxn];
struct node
{
	ll x;
	int id;
	node(ll t1,int t2)
	{
		x=t1,id=t2;
	}
	bool operator<(const node& t)const
	{
		return x>t.x;
	}
};
priority_queue<node>q;
void toposort()
{
	for(int i=0;i<n;i++)
	if(!d[i])q.push(node(b[i],i));
	for(int i=1;i<=n;i++)
	{
		node e=q.top();q.pop();
		int k=e.id;
		a[i]=e.x;
		for(int j=0;j<G[k].size();j++)
		{
			int v=G[k][j];
			d[v]--;
			if(d[v]==0)
			q.push(node(b[v],v));
		}
	}
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>b[i];
		if(b[i]%n!=i)
		for(int j=b[i]%n;;j++)
		{
			int k=j%n;
			if(k==i)break;
			G[k].push_back(i);
			d[i]++;
		}
	}
	toposort();
	for(int i=1;i<n;i++)printf("%d ",a[i]);
	printf("%d\n",a[n]);
}

F.逆序对!

我们枚举a[ i ]和a[ j ](j>i),然后进行数位dp算逆序贡献,先把m换成二进制,从高位到低位枚举,假设a[ i ]为 101xx,a[ j ]为100xx,a[ i ]和a[ j ]从高位枚举在第3位开始不同, 假设m当前枚举到了2位(即二进制10),我们发现所有的x<=10,同时异或a[ i ],a[ j ],a[ i ]>a[ j ],那么对答案的贡献就是2^1,假设m当前枚举到得到是第3位(即100),我们只有只有100异或他们才会不造成贡献,因此此时对答案的贡献是2^2-1,假设m枚举的是第4位,我们不难发现2^3只有一半的数才会对答案造成贡献,我只分析一半,剩下给大家了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1005,mod=998244353;
int b[maxn],a[35],cnt;
ll ans;
void add(ll& x,ll y)
{
	x=(x+y)%mod;
}
int dfs(int x,int y,int k)
{
	if(!k)return 0;
	if(!a[k])return dfs(x,y,k-1);
	int tp=0,p;
	for(int i=29;i>=0;i--)
	{
		int t1=0,t2=0;
		if(x&(1<<i))t1=1;
		if(y&(1<<i))t2=1;
		if(t1!=t2)
		{
			p=i+1;
			if(t1)tp=1;
			break; 
		}
	}
	int res=0,all=(1<<k-1);
	if(p>k)res=all;
	else if(p==k)res=all-1;
	else res=all/2;
	if(!tp)res=all-res;
	return res+dfs(x^(1<<k-1),y^(1<<k-1),k-1);
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	cin>>b[i];
	while(m)
	{
		a[++cnt]=m%2;
		m/=2;
	}
	for(int i=1;i<n;i++)
	for(int j=i+1;j<=n;j++)
	add(ans,dfs(b[i],b[j],cnt));
	cout<<ans<<endl;
}

G.抢红包机器人

update:最近一个月已经被人hacked起码有5次了(我枯了),已被hacked,谢谢网友的指出,数据 5 3 5 1 2 3 4 5 3 3 2 1 2 5 4,推荐一个暴力解法: wzazzy

阅读理解题,机器人a可能在b前面,也可能在b的后面,是不是有点像强连通定义?那就对了,我们按照顺序连接ai-->ai+1建立有向图,求强连通,最小的强连通分量的大小就是答案。

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
vector<int>G[maxn];
int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt,vis[maxn];
stack<int>S;
void dfs(int u)
{
	pre[u]=lowlink[u]=++dfs_clock;
	S.push(u);
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(!pre[v])
		{
			dfs(v);
			lowlink[u]=min(lowlink[u],lowlink[v]);
		}else if(!sccno[v])
		{
			lowlink[u]=min(lowlink[u],pre[v]);
		}
	}
	if(lowlink[u]==pre[u])
	{
		scc_cnt++;
		for(;;){
			int x=S.top();S.pop();
			sccno[x]=scc_cnt;
			if(x==u)break;
		}
	}
}
void find_scc(int n){
	dfs_clock=scc_cnt=0;
	memset(sccno,0,sizeof(sccno));
	memset(pre,0,sizeof(pre));
	for(int i=1;i<=n;i++)
	if(!pre[i])dfs(i);
}
int a[105];
int main()
{
	int n,m,k,ans=105;
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>k;
		for(int j=1;j<=k;j++)cin>>a[j];
		for(int j=1;j<k;j++)
		G[a[j]].push_back(a[j+1]);
	}
	find_scc(n);
	for(int i=1;i<=n;i++)
	vis[sccno[i]]++;
	for(int i=1;i<=scc_cnt;i++)
	ans=min(ans,vis[i]);
	cout<<ans;
}

J.强壮的排列

待补

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值