2015上海大都会邀请赛参赛总结
第一次参加邀请赛,我们队还是依旧太弱了,感觉还有很多东西需要去看。
事后补一下题目。
A. A - Article
题目意思:DRD使用word去敲一篇文章,文章有n个字符,在i+0.1的时刻可以敲一个字符,在i-0.1的时刻,word有p的概率会崩溃,如果崩溃就会重启,返回上一次保存的地方,在i时刻,可以选择按ctrl-s去保存文章,需要说明的是ctrl-s需要按x个字符,而这x个字符可以在i时刻瞬间完成,并且不会崩溃,问DRD如果想敲完这篇文章,最少的敲字符期望个数。
思路: 这道题,每次看都有新的发现, 先不考虑保存,那么敲完i个字符的期望为 f[i]=(f[i-1]+1)*(1-p) + (f[i-1]+1+f[i])*p; 为什么会这样? 首先考虑,不崩溃的情况,就是i-1个字符的期望再敲一个字符,不崩溃的概率为1-p, 然后考虑,崩溃的情况, 如果崩溃的话, 敲的字符个数就为f[i-1]+1+f[i], 概率为p, 综合考虑后,就可以列出来这个式子。
那么如果考虑保存F[i]=f[i]+x;
如果保存, 那么每按一个ctrl-s就可以看做一个阶段, 每个阶段之间互相没有影响,每个阶段的期望可以直接相加。
第一种思路: 枚举或者三分ctrl-s的个数, 要想期望最少,贪心的思路是平均分配, 注意怎么平均分配。
第二种思路: DP dp[i]=min(dp[i], dp[i-k]+f[k]+x)
代码:
#include<bits/stdc++.h>
#define INF 0x7f7f7f7f
using namespace std;
const int N=100010;
double f[N];
int n,x;
double p;
void init()
{
f[0]=0;
for (int i=1;i<=n;i++) f[i]=(f[i-1]+1)/(1-p);
}
double solve(int m)
{
double sum=0;
if (n%m==0) sum=m*(f[n/m]+x);
else
{
sum=(n%m)*(f[n/m+1]+x);
sum+=(m-n%m)*(f[n/m]+x);
}
return sum;
}
int main()
{
int T,Case=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%lf%d",&n,&p,&x);
init();
int l=1,r=n,m1,m2,m;
double ans=INF,a1,a2;
while(l<=r)
{
m=(l+r)/2;
m1=(l+m)/2; m2=(m+r)/2;
a1=solve(m1);
a2=solve(m2);
if (a1-a2>=0.000001)
{
ans=min(ans,a2);
l=m1+1;
}
else
{
ans=min(ans,a1);
r=m2-1;
}
}
//double ans=INF;
//for (int i=1;i<=n;i++) ans=min(ans,solve(i));
printf("Case #%d: %0.6lf\n",++Case,ans);
}
return 0;
}
B B - Base64
题意: 把字符串s通过base64规则转换k次并且输出。 JAVA貌似有专门的类库~
比赛的时候, 手速太慢
代码:
#include <iostream> #include <string.h> #include <stdio.h> #include <string.h> using namespace std; char f[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char s[2][1000]; int len[2]; void solve(int p) { int sum=0,dig=5; memset(s[p^1],0,sizeof(s[p^1])); len[p^1]=0; for (int i=0;i<len[p];i++) { for (int j=7;j>=0;j--) { sum=sum+(((s[p][i]>>j)&1)<<dig); dig--; if (dig<0) { s[p^1][len[p^1]++]=f[sum]; sum=0; dig=5; } } } if (dig==3) { s[p^1][len[p^1]++]=f[sum]; s[p^1][len[p^1]++]='='; s[p^1][len[p^1]++]='='; } if (dig==1) { s[p^1][len[p^1]++]=f[sum]; s[p^1][len[p^1]++]='='; } } int main() { int T,Case=0,p,k; scanf("%d",&T); while(T--) { p=0; scanf("%d%s",&k,s[p]); len[0]=strlen(s[0]); len[1]=0; while(k--) { solve(p); p=p^1; } printf("Case #%d: %s\n",++Case,s[p]); } return 0; } /* 5 1 A 1 AA 2 A 1 Mike 4 Mike */
C. C - Calculator
待完成
D D - Doom
待完成
E E - EXAM
题意: DRD需要准备N场考试, 给出每场考试开始的时间ei和持续的时间li, 和最少需要准备的时间ri, 复习的时间可以不连续, 但是考试的时间一定是连续的, 问是否会挂科
题解:全场最水的模拟题, but , 因为Case后面没有加#号, W了好几发, 我和队友刚开始都没有检查出来, 真是手残。 另外在比赛后重现时"NO“ 打成"N0"~~~
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N=100010;
long long f[N];
struct node
{
long long r,e,l;
};
node p[N];
bool cmp(node a, node b)
{
return a.e<b.e;
}
int main()
{
int T,n,Case=0;
bool flag;
cin>>T;
while(T--)
{
memset(f,0,sizeof(f));
cin>>n;
for (int i=1;i<=n;i++) scanf("%I64d%I64d%I64d",&p[i].r,&p[i].e,&p[i].l);
sort(p+1,p+n+1,cmp);
flag=true;
for (int i=1;i<=n;i++)
{
f[i]=f[i-1]+p[i].r;
if (f[i]>p[i].e)
{
flag=false;
break;
}
f[i]=f[i]+p[i].l;
}
if (flag) printf("Case #%d: YES\n",++Case);
else printf("Case #%d: N0\n",++Case);
}
return 0;
}
F F - Friends
题意: 给出10个人之间掌握语言的一个关系图,问一共可能有多少种情况
题解: 可以这样考虑, 每种语言之间都是相互独立的, 那么就可以利用乘法法则, 一种语言的情况为32, 那么N种就为32^N
代码:
import java.util.*;
import java.math.*;
public class Main {
public static void main(String args[])
{
Scanner cin = new Scanner(System.in);
BigInteger sum;
BigInteger p= new BigInteger("32");
int T,Case=0,n;
T=cin.nextInt();
while(true)
{
T--;
if (T<0) break;
n=cin.nextInt();
sum=BigInteger.ONE;
for (int i=1;i<=n;i++) sum=sum.multiply(p);
Case++;
System.out.println("Case #"+Case+": "+sum);
}
}
}
G - Game
题意: 给出一颗树, 从根找出K条路径, 每条路径上的值加起来使其最大, 有一个地方需要注意, 同一个结点的值不能重复加。
题解:
注意 使用long long
第一种方法是使用线段树来维护更新
首先DFS, 记录下每个结点的儿子结点DFS序的区间,和每个点的父亲结点,以及从跟到每个结点的值。
把区间(1,n) 建立一颗线段树, 这里的1和n为每个结点的DFS序, 在询问每个结点信息的时候需要translate下, 在线段树中需要维护的是一个最大值和最大值的ID。
K次取最大值操作, 每次都需要把根结点和父亲结点所在的DFS序区间更新。 每个结点的信息只更新一次。
输出最后结果。
第二种方法是一种比较巧妙的自下而上的更新方式, 学习了
第一种代码:
#include <stdio.h>
#include <string.h>
#define LL long long
using namespace std;
const int N=100010;
struct node
{
int id;
LL sumv,pushv;
};
int Next[N],to[N],head[N],id,idx;
int fa[N],ll[N],rr[N],translate[N];
LL w[N],sum[N];
node tree[N<<2];
void init()
{
memset(head,0,sizeof(head));
id=1;
idx=0;
}
void addedge(int a, int b)
{
Next[id]=head[a];
to[id]=b;
head[a]=id++;
}
void dfs(int u, int pre, LL tmp)
{
fa[u]=pre;
sum[u]=tmp+w[u];
ll[u]=++idx;
for (int i=head[u];i!=0;i=Next[i]) dfs(to[i],u,sum[u]);
rr[u]=idx;
}
void build(int v, int l, int r)
{
if (l==r)
{
tree[v].sumv=sum[translate[l]];
tree[v].pushv=0;
tree[v].id=translate[l];
return;
}
tree[v].pushv=0;
int mid=(l+r)/2;
build(v*2,l,mid);
build(v*2+1,mid+1,r);
if (tree[v*2].sumv>tree[v*2+1].sumv)
{
tree[v].id=tree[v*2].id;
tree[v].sumv=tree[v*2].sumv;
}
else
{
tree[v].id=tree[v*2+1].id;
tree[v].sumv=tree[v*2+1].sumv;
}
}
void push_down(int v)
{
if (tree[v].pushv!=0)
{
tree[v*2].pushv+=tree[v].pushv;
tree[v*2+1].pushv+=tree[v].pushv;
tree[v*2].sumv+=tree[v].pushv;
tree[v*2+1].sumv+=tree[v].pushv;
}
tree[v].pushv=0;
}
void update(int v, int l, int r, int L, int R,LL value)
{
if (L<=l&&r<=R)
{
tree[v].sumv+=value;
tree[v].pushv+=value;
return;
}
push_down(v);
int mid=(l+r)/2;
if (L<=mid) update(v*2,l,mid,L,R,value);
if (R>mid) update(v*2+1,mid+1,r,L,R,value);
if (tree[v*2].sumv>tree[v*2+1].sumv)
{
tree[v].id=tree[v*2].id;
tree[v].sumv=tree[v*2].sumv;
}
else
{
tree[v].id=tree[v*2+1].id;
tree[v].sumv=tree[v*2+1].sumv;
}
}
int main()
{
int T,Case=0,n,k,a,b;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++) scanf("%I64d",&w[i]);
for (int i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
addedge(a,b);
}
dfs(1,0,0);
for (int i=1;i<=n;i++) translate[ll[i]]=i;
n=idx;
build(1,1,n);
LL ans=0;
while(k--)
{
ans+=tree[1].sumv;
int u=tree[1].id;
while(u!=0&&w[u]!=0)
{
update(1,1,n,ll[u],rr[u],-w[u]);
w[u]=0;
u=fa[u];
}
}
printf("Case #%d: %I64d\n",++Case,ans);
}
return 0;
}
/*
4
5 2
4 3 2 1 1
1 2
1 5
2 3
2 4
5 3
4 3 2 1 1
1 2
1 5
2 3
2 4
5 2
4 3 2 1 1
1 2
1 5
2 3
2 4
5 3
4 3 2 1 1
1 2
1 5
2 3
2 4
*/
第二种:
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
int n, k;
const int N = 100000 + 10;
struct edge
{
int next, to;
}e[2*N];
int head[N], tot;
void init()
{
memset(head, 0, sizeof(head));
tot = 1;
}
void add(int u, int v)
{
e[tot].next = head[u];
e[tot].to = v;
head[u]= tot++;
}
int a[N], fa[N];
struct node
{
int id;
long long maxv;
}Q[N];
long long maxv[N];
void dfs(int u, int p)
{
fa[u] = p;
Q[u].id = -1;
for(int i = head[u]; i != 0; i = e[i].next)
if(e[i].to != p)
{
dfs(e[i].to, u);
if(Q[u].id == -1 || Q[u].maxv < Q[e[i].to].maxv)
{
Q[u].id = Q[e[i].to].id;
Q[u].maxv = Q[e[i].to].maxv;
}
}
if(Q[u].id == -1)
{
Q[u].maxv = 0;
Q[u].id = u;
}
Q[u].maxv += a[u];
}
bool operator < (node a, node b)
{
return a.maxv < b.maxv;
}
bool vis[N];
int main()
{
int T;
scanf("%d", &T);
for(int cas = 1; cas <= T; cas++)
{
init();
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
int u, v;
for(int i = 1; i < n; i++)
{
scanf("%d%d", &u, &v);
add(u, v);
}
dfs(1, 0);
priority_queue<node> que;
que.push(Q[1]);
long long ans = 0;
while(k--)
{
if(que.empty())
break;
node tmp = que.top();
que.pop();
ans += tmp.maxv;
u = tmp.id;
while(fa[u] !=0)
{
v = fa[u];
for(int i = head[v]; i != 0; i = e[i].next)
if(e[i].to != u)
{
que.push(Q[e[i].to]);
fa[e[i].to] = 0;
}
fa[u] = 0;
u = v;
}
}
printf("Case #%d: %I64d\n", cas, ans);
}
return 0;
}
H - Homework
待完成
I - inverse
待完成
J - Joyful
题意: 给出一个N*M的矩阵, 进行K此操作,每次操作随机选取两个点(x1,y1) (x2,y2), 两个点组成一个矩形, 这个矩形内的数字就被选中, 每个矩形单元内的数字选中只能被记为一次, 问进行K此操作,选中点个数的期望。
题解: 每个点都是相互独立的, 可以以这个点为中心,划分为9个区域, 分别算出来每个点被一次选中的概率p, 那么两次就是1-(1-p)^2, 最后累加起来就是最后结果。

代码:
#include <cstdio>
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
int T,Case=0;
long long n,m,k;
double p,ans;
scanf("%d",&T);
while(T--)
{
scanf("%I64d%I64d%I64d",&m,&n,&k);
ans=0;
double c=n*m*n*m*1.0,pp;
for (long long i=1;i<=m;i++)
for (long long j=1;j<=n;j++)
{
p=0;
p+=(i-1)*(j-1)*(m-i+1)*(n-j+1)*1.0/c;
p+=(i-1)*(m-i+1)*n*1.0/c;
p+=(i-1)*(n-j)*(m-i+1)*j*1.0/c;
p+=(j-1)*m*(n-j+1)*1.0/c;
p+=(n*m*1.0)/c;
p+=(n-j)*m*j*1.0/c;
p+=(m-i)*(j-1)*i*(n-j+1)*1.0/c;
p+=(m-i)*i*n*1.0/c;
p+=(m-i)*(n-j)*i*j*1.0/c;
p=1-p;
pp=p;
for (long long t=2;t<=k;t++) p=p*pp;
ans=ans+1.0-p;
}
printf("Case #%d: %0.lf\n",++Case,ans);
}
return 0;
}
浙公网安备 33010602011771号