您的位置:首页 > 大数据 > 人工智能

2016 Multi-University Training Contest 1

2016-08-21 22:42 351 查看
Abandoned country

依稀记得这题是我和熊神两个人怼的, 比赛中是T : 没有在并查集中压缩路径

然后后来wa 了一发, 原因是 莫名其妙 把 ans 的long long 改成double 就可以了,据说double是128位。

题意是说:第一个问题是跑最小生成树,跑完后求 在图中任意两点距离的期望

这个题是队友读题,然后他卡了个地方,貌似是图中每条边使用的次数,然后可以用一个dfs 解决 ,统计被用过多少次即可。

!!!!! 切记切记 并查集一定不要写错啊!!!!!!!!!!!!

奇怪的是下面这段代码ans 用longlong定义会wa,可能是运算过程超过了吧。。。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
#define inf 99999999
struct po {
int u,v, w;
po(){}
po(int _u,int _v,int _w){u=_u;v=_v;w=_w;}
po(int _v,int _w){v=_v;w=_w;}
}p[1000010];
//vector<po>g[100010];
//vector<int>g1[100010],g2[100010];
struct Edge{
int u,to,dis,next;
}edge[1000010*3];

bool cmp(po a, po b) {
return a.w <= b.w;
}
int f[100010];
int find(int x) {  // 记得压缩路径!
if(x!=f[x]){
f[x]=find(f[x]);
}
return f[x];
}
int n,m;
int cnt;
int head[100010];
void addedge(int u,int v,int d){
edge[cnt].u=u;
edge[cnt].to=v;
edge[cnt].dis=d;
edge[cnt].next=head[u];
head[u]=cnt++;
}
__int64 kruskal() {
__int64 ans = 0, a, b;
sort(p, p + m, cmp);
for (int i = 0; i < m; i++) {
a = find(p[i].u);
b = find(p[i].v);
if (a != b) {
f[a] = b;
ans+=p[i].w;
addedge(p[i].u,p[i].v,p[i].w);
addedge(p[i].v,p[i].u,p[i].w);
}
}
return ans;
}
int num[100010];
int valu[100010];
double ans=0;
void init(){
memset(head,-1,sizeof(head));
memset(valu,0,sizeof(valu));
memset(num,0,sizeof(num));
cnt=0;
ans=0;
}
int dfs(int rot,int pre)
{
num[rot]=1;
//    printf("rot=%d\n",rot);
for(int i=head[rot];i!=-1;i=edge[i].next){
int v=edge[i].to;
//        printf("i=%d v=%d head=%d\n",i,v);
if(v==pre) continue;
valu[v]=edge[i].dis;
num[rot]+=dfs(v,rot);
}
ans+=(double) (valu[rot])*num[rot]*(n-num[rot]);
return num[rot];
}
int main() {
int T;
scanf("%d",&T);
while (T--) {
scanf("%d%d",&n,&m);
init();
int u,v,w;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&w);
p[i]=po(u,v,w);
}
for (int i = 1; i <= n; i++)
f[i] = i;
printf("%I64d ", kruskal());
dfs(1,1);
printf("%.2lf\n",ans*1.0/(n*(n-1.0)/2.0));
}
return 0;
}


Chess

我看了题,是博弈的话,就丢给队友了,然后队友也过了。。。赛后就没咋看了,今天来重新拾起来修炼修炼。

一个n*20的棋盘,然后输入每行有几个棋子,以及位置。 然后规则就是每个棋子可以往右边移动,如果右边有棋子,可以跳过右边的棋子,但每个棋子不能下到棋盘外面,也不能够两个棋子下到一个格子上。

先手能赢 yes,否则no

sg函数,预处理必胜点和必败点

这里写代码片


GCD

队友线段过了这题

后来看了看,暴力似乎也可以过= =

但是询问 l,r 的GCD 确实可以线段树询问

说一下预处理的想法吧:

我们可以暴力处理,开几个空间,用map或者vector都可以,用来操作;

在循环扫一遍 数组a的时候

我们可以把数组a 的a[i]放在一个空间X里面,然后我们吧 这个空间X的所有内容都 和 a[i]求一遍GCD,再把这些个GCD放进空间X, 为了 防止重复可以 开一个空间 Y。 具体看操作就行。

这样做的时间复杂度我以为会超时,但后来看到有人这样过了, 据说 小于n的子区间的gcd种类数最多为logn个? 这咋证呢

1 2 3 4 5 6 7 8 , 小于8的子区间 gcd 有1,2,3,4,5,6,7 如果不算 [i,i,]这种gcd 那么就只有 1,2,4 三个

应该就是这个道理了吧= =

哇草,被这个傻逼编译器摆了一大道

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#define mem(a) memset(a,0,sizeof(a))
#define ll __int64
#define INF 0x7fffffff   //INT_MAX
#define inf 0x3f3f3f3f   //
const double PI = acos(-1.0);
const double e = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
using namespace std;
struct seg{
int l,r;
ll v;
int flag;
}st[100005<<2];
ll a[100005];
int n;
void push_up(int rt){
st[rt].v=gcd(st[rt<<1].v , st[(rt<<1)+1].v);
}
/*
* 尼玛的 左移都不会写了???????????????????????????????
* 1<<rt????????????????????????????????
* 1左移 rt?????????????????????????????????
*
*/
void build(int l,int r,int rt){
st[rt].v=0;
st[rt].l=l;
st[rt].r=r;
if(l==r){
st[rt].v=a[l];
//      cout<<l<<" "<<a[l]<<endl;
return;
}
int mid=(l+r)/2;
build(l,mid,rt*2);
build(mid+1,r,(rt<<1)+1);
push_up(rt);
}
ll qur(int L,int R,int l,int r,int rt){
//  printf("rt=%d %I64d\n",rt,st[rt].v);
//  printf("L=%d R=%d\n",L,R);
if(L==l && r==R){
return st[rt].v;
}
ll ans=0;
push_up(rt);
int mid=(L+R)>>1;
if(mid>=r){
ans=qur(L,mid,l,r,rt<<1);
}
else if(mid<l){
ans=qur(mid+1,R,l,r,(rt<<1)+1);
}
else
ans=gcd(qur(L,mid,l,mid,rt<<1),qur(mid+1,R,mid+1,r,(rt<<1)+1 ));
return ans;
}
map<ll,ll>X,Y,cnt;
int test;

int main(){
int t;
scanf("%d",&t);
test=1;
while(t--){
printf("Case #%d:\n",test++);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%I64d\n",&a[i]);
build(1,n,1);
X.clear();
Y.clear();
cnt.clear();
map<ll,ll>::iterator it;
for(int i=1;i<=n;i++){
cnt[a[i]]++; //gcd= a[i] 增加
X[a[i]]++;
for(it=Y.begin();it!=Y.end();it++){  // 据说这里是logn
int flag=gcd(it->first,a[i]);
X[flag]+=it->second;
cnt[flag]+=it->second;
}
Y.clear();
for(it=X.begin(); it!=X.end();it++){
Y[it->first]+=it->second;
}
X.clear();
}

int q;
scanf("%d",&q);
while(q--){
int l,r;
scanf("%d %d",&l,&r);
ll ans=qur(1,n,l,r,1);
printf("%I64d %I64d\n",ans,cnt[ans]);
}
}
return 0;
}


还有个计算几何题,

套套公式就OK
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: