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=sum∗137+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;
}