A. Rainbow的信号
很巧妙,适宜反复赏玩
code :
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 3;
int n,last[3],a[maxn],b[maxn];
double ansxor,ansand,ansor;
void Rainbow(int k)
{
last[0]=last[1]=0;
int c1=0,c2=0;
double w=(1<<k)*1.0/n/n;//最后写成/(n*n)就爆int了
for(int i=1;i<=n;i++) {
b[i]=(a[i]>>k)&1;
if(b[i])/*区间长度为1即l=r=i*/ {
ansxor+=w;
ansand+=w;
ansor+=w;
}
//以下计算长度大于等于2的区间
if(!b[i]) ansor+=2*w*last[1];
else {
ansand+=2*w*(i-1-last[0]); //减1是因为区间[r,r]已经被计算过了
ansor+=2*w*(i-1);
}
ansxor+=2*w*(b[i]?c1:c2);
c1++;
if(b[i]) swap(c1,c2);
last[b[i]]=i;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=0;i<31;i++) Rainbow(i);
printf("%.3lf %.3lf %.3lf",ansxor,ansand,ansor);
return 0;
} B. 绿豆蛙的归宿
算期望,倒推计算,建反图的思想
code :
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 3;
int tot,ver[maxn],head[maxn],Next[maxn],edge[maxn],deg[maxn],out[maxn];
double d[maxn];
void add(int x,int y,int z)
{
ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;
}
void bfs(int s)
{
queue<int> q;
q.push(s);
while(!q.empty())
{
int x=q.front(),y,z;
q.pop();
for(int i=head[x];i;i=Next[i]) {
y=ver[i],z=edge[i];
d[y]+=(d[x]+z)/out[y];
deg[y]--;
if(!deg[y]) q.push(y);
}
}
}
int main()
{
int n,m,a,b,c;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
scanf("%d%d%d",&a,&b,&c);
deg[a]++; out[a]++;//反图中的入度,原图中的出度,两者等价
add(b,a,c);//建原图的反图
}
bfs(n);//从n倒着算到1
printf("%.2lf",d[1]);
return 0;
} C. 扑克牌
code :


京公网安备 11010502036488号