AtCoder Beginner Contest 226

AtCoder Beginner Contest 226 - AtCoder
B - Counting Arrays

这个题目就是看有几个不同的序列,然后可以使用哈希来做,然后用 m a p map map来存, s u m = s u m ∗ 137 + 47 + a [ i ] sum=sum*137+47+a[i] sum=sum137+47+a[i],然后这样子貌似就可以过了,然后其实还可以转换成字符串,将空格转换成逗号然后再放在 m a p map map里面去重,或者用 s e t set set也行的,听说用 v e c t o r vector vector存起来,然后用 m a p map map标记也可以过

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#define int long long 
using namespace std;
int n,cnt,x,ans;
map<int,int> m;
signed main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&cnt);
		int now=0;
		for(int i=1;i<=cnt;i++){
			scanf("%lld",&x);
			now=now*137+47+x;
		}
		if(m[now]==0) m[now]=true,ans++;
	}
	printf("%lld\n",ans);
	return 0;
}

C - Martial artist

这个就是递归吧,然后加一下,标记一下就行了

#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 300000
#define int long long
using namespace std;
int ans,n,t[maxn],cnt,k,head[maxn];
bool book[maxn];
struct node{
	int to,next;
}edge[maxn*2];
void add(int u,int v){
	edge[++k].next=head[u];
	edge[k].to=v;
	head[u]=k;
}
void dfs(int u){
	for(int i=head[u];i;i=edge[i].next){
		int v=edge[i].to;
		if(book[v]) continue;
		dfs(v);
	}
	book[u]=true; ans+=t[u];
}
signed main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld %lld",&t[i],&cnt);
		for(int j=1,v;j<=cnt;j++){
			scanf("%lld",&v);
			add(i,v);
		}
	}
	dfs(n);
	printf("%lld\n",ans);
	return 0;
}

D - Teleportation

这个题目一开始理解错误了,意思就是要重复使用法术 ( a , b ) (a,b) (a,b)来到达 ( x 0 , y 0 ) (x_0,y_0) (x0,y0),而不是先用用这个法术,再用用那个法术,所以就很明显了, n 2 n^2 n2的去处理两两个点,将 ( x , y ) (x,y) (x,y)转换成 ( x g c d , y g c d ) (\frac{x}{gcd},\frac{y}{gcd}) (gcdx,gcdy),然后存起来,最后进行排序,依次比较, 0 0 0 x x x要特别处理,把 x x x变成 1 1 1或者 − 1 -1 1

#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 600
#define int long long
using namespace std;
int n,x[maxn],y[maxn],ans,k;
struct node{
	int xx,yy;
}a[maxn*maxn*2];
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
bool cmp(node a,node b){
	return a.xx==b.xx?a.yy<b.yy:a.xx<b.xx;
}
signed main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++) scanf("%lld %lld",&x[i],&y[i]);
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			a[++k].xx=x[i]-x[j];
			a[k].yy=y[i]-y[j];
			a[++k].xx=x[j]-x[i];
			a[k].yy=y[j]-y[i];
		}
	}
	for(int i=1;i<=k;i++){
		if(a[i].xx==0 || a[i].yy==0){
			if(a[i].xx==0){
				if(a[i].yy>0) a[i].yy=1;
				else a[i].yy=-1;
			}else{
				if(a[i].xx>0) a[i].xx=1;
				else a[i].xx=-1;
			}
		}else{
			int tempx=a[i].xx,tempy=a[i].yy;
			a[i].xx=abs(a[i].xx);
			a[i].yy=abs(a[i].yy);
			int temp=gcd(a[i].xx,a[i].yy);
			a[i].xx/=temp;
			a[i].yy/=temp;
			if(tempx<0) a[i].xx*=-1;
			if(tempy<0) a[i].yy*=-1;
		}
	}
	sort(a+1,a+1+k,cmp);
	for(int i=1;i<=k;i++){
		if(a[i].xx!=a[i-1].xx || a[i].yy!=a[i-1].yy) 
		ans++;
	}
	printf("%lld\n",ans);
	return 0;
}

E - Just one

题意就是给出一个无向图(可能不联通),然后求出有多少种给边定向的方案,使得每一个点最多有一个出度

  • 然后对于每一个连通块来说,只要边数 > > >点数,那就肯定不行,必须有一个点有两个出度,所以答案就为 0 0 0
  • 如果是一条链或者说没有环的时候也是不行的,因为这样的时候有一个点是没有出度的
  • 其他情况这个连通块都只有 2 2 2种答案,是环的就是顺时针 + + +逆时针就完了,然后其他的都向这个环的方向指过来就行了.
  • 连通块可以用并查集来实现,不要被环影响而去想缩点了….
#include<cstdio>
#include<algorithm>
#include<cstring>
#define mod 998244353
#define maxn 200100
using namespace std;
int n,m,fa[maxn],cnt[maxn],edge[maxn],ans=1;
bool book[maxn];
int findf(int x) {return fa[x]==x?x:fa[x]=findf(fa[x]);}
signed main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) cnt[i]=1,fa[i]=i;
	for(int i=1,u,v;i<=m;i++){
		scanf("%d %d",&u,&v);
		int x=findf(u);
		int y=findf(v);
		if(x!=y) {
			cnt[x]+=cnt[y];
			edge[x]+=edge[y]+1;
			fa[y]=x;
		}else edge[x]++;
	}
	for(int i=1;i<=n;i++){
		int temp=findf(i);
		if(edge[temp]>cnt[temp] || edge[temp]==cnt[temp]-1) printf("0"),exit(0);
		if(book[temp]) continue;
		ans=ans*2%mod; book[temp]=true;
	}
	printf("%d\n",ans);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

d3ac

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

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

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

打赏作者

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

抵扣说明:

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

余额充值