转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
第二次周赛,由#84的div1以及#83的div2的AB组成
#83 div2 A 直接枚举,秒数+1
#83 div2 B 两个n位的二进制数相乘,结果最多为2*n位(二进制),根据这个,排序后判断
#84 div1 A 直接枚举,从少到多,枚举7的个数,7的个数越多,位数就越少,数字就越小。
结果显然是4在前,7在后
#84 div B
这题 有点蛋疼,我的做法是,首先预处理出所有的lucky number
然后开始枚举a[i],表示左端点要保存a[i]能取,但是a[i-1]不取,那么右端点就要保证b[i+k-1]能取,但是b[i+k]不能取
分别以A为左端点扫描一遍,B为左端点扫描一遍。
但是这样会忽视掉一种情况,就是K=1的情况,有可能左端点和右端点重合,如[4,4]刚好有一个lucky number。
所以要遍历一遍, 去重
int vl,vr,pl,pr,k;
vector<int>a;
void bfs()
{
queue<int>que;
que.push(0);
while(!que.empty())
{
int u=que.front();
que.pop(); if(u>1e8) continue;
int tmp=u*10+4;
if(tmp>1e9||tmp<0) ;else {que.push(tmp);a.pb(tmp);}
tmp=u*10+7;
if(tmp>1e9||tmp<0) ;else {que.push(tmp);a.pb(tmp);}
}
}
int main()
{
a.pb(0);
bfs();
// for(int i=1;i<a.size();i++) printf("%d\n",a[i]);
a.pb(1000000005);
// freopen("1.in","r",stdin);
while(scanf("%d%d%d%d%d",&vl,&vr,&pl,&pr,&k)!=EOF)
{
LL tot=(LL)(vr-vl+1)*(pr-pl+1);
LL tmp=0,cnt=0;
if(k==1)
{
for(int i=1;i<a.size()-1;i++) if(a[i]>=vl&&a[i]<=vr&&a[i]>=pl&&a[i]<=pr) cnt++;
}
for(int i=1;i<a.size()-k+1-1;i++)
{
if(a[i]<vl) continue;
if(a[i-1]>=vr) continue;
if(a[i+k-1]>pr) continue;
if(a[i+k]<=pl) continue;
tmp+=(LL)(min(vr,a[i])-max(a[i-1]+1,vl)+1)*(min(pr,a[i+k]-1)-max(pl,a[i+k-1])+1);
}
for(int i=1;i<a.size()-k+1-1;i++)
{
if(a[i]<pl) continue;
if(a[i-1]>=pr) continue;
if(a[i+k-1]>vr) continue;
if(a[i+k]<=vl) continue;
tmp+=(LL)(min(pr,a[i])-max(a[i-1]+1,pl)+1)*(min(vr,a[i+k]-1)-max(vl,a[i+k-1])+1);
}
printf("%.10f\n",(tmp-cnt)*1.0/tot);
}
return 0;
}
#83 div1 C
一个树DP,处理从一个点出发,到达多少个点的路径中会出现Lucky nubmer。
果然tree_dp不是我的料,写得很渣。
以1为根,处理出所有子树的size
然后向下更新,表示从当前结点,往下遍历,会有多少个点的路径上出现lucky number。显然,如果当前路径便是lucky number,便直接加上size,否则加上孩子的down。
然后向上更新,表示从当前结点,往上遍历,会有多少个点的路径上出现lucky number。显然如果从父亲到当前节点的路径为Lucky number,便直接加上上面的所有节点数目,n-size[v]。否则便要算上父节点的向上更新以下,当前节点的所有兄弟结点(便是父亲的向下更新,减去当前的向下更新)
一般的一次DP就解决了,哎太弱了
struct Edge
{
int v,next;
int f;
}e[N];
int cnt=0,start[N],sz[N];
int down[N],up[N];
set<int>a;
int n;
void add(int u,int v,int f)
{
e[cnt].v=v;e[cnt].f=f;e[cnt].next=start[u];
start[u]=cnt++;
e[cnt].v=u;e[cnt].f=f;e[cnt].next=start[v];
start[v]=cnt++;
}
void bfs()
{
queue<int>que;
que.push(0);
while(!que.empty())
{
int u=que.front();
que.pop();
int tmp=u*10+4;
if(tmp>1e9||tmp<0) ;else {que.push(tmp);a.insert(tmp);}
tmp=u*10+7;
if(tmp>1e9||tmp<0) ;else {que.push(tmp);a.insert(tmp);}
}
}
void fuck1(int u,int pre)
{
sz[u]=1;
for(int i=start[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
if(v==pre) continue;
fuck1(v,u);
sz[u]+=sz[v];
}
}
void fuck2(int u,int pre)
{
for(int i=start[u];i!=-1;i=e[i].next)
{
int f=e[i].f,v=e[i].v;
if(v==pre) continue;
fuck2(v,u);
if(f) down[u]+=sz[v];
else down[u]+=down[v];
}
}
void fuck3(int u,int pre)
{
for(int i=start[u];i!=-1;i=e[i].next)
{
int v=e[i].v,f=e[i].f;
if(v==pre) continue;
if(f) up[v]+=n-sz[v];
else {up[v]+=up[u];
up[v]+=down[u]-down[v];
}
fuck3(v,u);
}
}
int main()
{
bfs();
mem(start,-1);
scanf("%d",&n);
mem(up,0);mem(down,0);
for(int i=1;i<n;i++)
{
int f,u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(a.find(w)==a.end()) f=0;
else f=1;
add(u,v,f);
}
fuck1(1,0);
fuck2(1,0);
fuck3(1,0);
LL ans=0;
for(int i=1;i<=n;i++)
{
ans+=(LL)(up[i]+down[i]-1)*(up[i]+down[i]);
}
printf("%I64d\n",ans);
return 0;
}
#83 div1 D
是给出一个序列,给出交换规则(至少有一个数是lucky number)
给出的交换次数是2*n,输出任意解
找出一个lucky number用来和其它的交换
遍历所有位置,如果当前位置不是选中的lucky number的位置,则考虑交换,则Lucky number到了另一个位置,再考虑排序之后在这个位置的是哪个数,这个数的当前位置。
再将Lucky number换过去,这样从第一个位置开始遍历,最多两次交换可以把一个数归位。
最后我再把lucky number换到应该属于他自己的位置
另外其中有种数据,我的代码没有问题,结果CF的SPJ判我WA,便把if(i!=pos)省略了,结果就过了, 这不科学啊
其实这样也是对的,次数看上去是2*n+1次,但是绝不会出现这种情况,仔细想想就知道了。
int check(int n)
{
while(n)
{
int t=n%10;
if(t!=4&&t!=7) return 0;
n/=10;
}
return 1;
}
int n,a[N];
int b[N]; //表示应该排在第i个位置的数现在的位置
int c[N]; //表示第i个数最终放在哪
vector<pair<int,int> >ans;
bool cmp(int i,int j)
{
return a[i]<a[j];
}
void slove(int &x,int y)
{
if(x==y) return;
if(!check(a[x])&&!check(a[y])) puts("error");
swap(a[x],a[y]);
ans.pb(mp(x,y));
swap(c[x],c[y]);
b[c[x]]=x;
b[c[y]]=y;
x=y;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],b[i]=i;
sort(b+1,b+1+n,cmp);
int pos=-1;
for(int i=1;i<=n;i++) c[b[i]]=i;
for(int i=1;i<=n;i++) if(check(a[i])) {pos=i;break;}
if(pos==-1)
{
int flag=1;
for(int i=1;i<n;i++)if(a[i]>a[i+1]) flag=0;
puts(flag?"0":"-1");
return 0;
}
for(int i=1;i<=n;i++)
{
// if(i!=pos)
{
slove(pos,i);
slove(pos,b[i]);
}
}
slove(pos,b[pos]);
cout<<ans.size()<<endl;
for(int i=0;i<ans.size();i++) cout<<ans[i].first<<" "<<ans[i].second<<endl;
return 0;
}