【20151105noip膜你赛】bzoj3652 bzoj3653
题目仿佛在讽刺我。。。

第一题:

题解:
考虑枚举区间右端点,维护所以左到当前的 and 和 or 。注意 and 每次变化至少有一个二进制位从1变 0,or 每次至少有一个位从0变 1,所以最多有log段不同的值。用两个链表维护这log个值,暴力计算答案即可。
O( nlogn)
我原本打的是一个树状数组的O(nlognlogn)算法。。然后被卡了。。只有50分。。
看了看奥爷爷的代码,发现他直接用一个链表同时维护and和or值,真奇怪啊不是(logn)^2吗。。然后男神说这个也是log级别的,因为两个区间不同只能是边界上跨越。
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std; typedef long long LL;
const int N=;
const LL mod=;
int n,al;
struct node{int last,next;LL t0,t1,sum;}a[N]; int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
freopen("value.in","r",stdin);
freopen("value.out","w",stdout);
scanf("%d",&n);
al=;
int x,last=;
LL ans=;
for(int i=;i<=n;i++)
{
scanf("%d",&x);
for(int j=last;j;j=a[j].last)
{
a[j].t0&=x;
a[j].t1|=x;
}
a[++al].t0=x;a[al].t1=x;a[al].sum=;
a[al].last=last;
if(last) a[last].next=al;
last=al; for(int j=last;j;j=a[j].last)
{
int p=a[j].last;
if(p && a[p].t0==a[j].t0 && a[p].t1==a[j].t1)
{
a[p].sum+=a[j].sum;
a[p].next=a[j].next;
if(a[j].next) a[a[j].next].last=p;
else last=p;//debug last=p not last=j
}
} for(int j=last;j;j=a[j].last)
{
ans=(ans+((((a[j].t0*a[j].t1)%mod)*a[j].sum)%mod))%mod;
}
}
printf("%I64d\n",ans);
return ;
}
第二题 bzoj3652
3652: 大新闻
Time Limit: 10 Sec Memory Limit: 512 MBSec Special Judge
Submit: 207 Solved: 106
[Submit][Status][Discuss]
Description

Input 两个整数n和p。p/100表示题目中描述的概率
Output 输出期望在模1000000007下的值
Sample Input
3 50
Sample Output
2
HINT

1<=N<=10^18
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std; typedef long long LL;
const LL mod=;
const int N=;
LL n,m,p,bit[N],vis[N][][],cnt[N][],f[N][][][][],g[N][][];
int d[N]; LL ad(LL x,LL y){return ((x+y)%mod+mod)%mod;} int find_vis(int x,int now,int flag)
{
if(x==) return ;
if(vis[x][now][flag]!=-) return vis[x][now][flag];
int mx=;if(flag || (x-==)) mx=d[x-];
LL ans=;
for(int i=;i<=mx;i++)
{
ans=ad(ans,find_vis(x-,i,flag&(i==d[x-])));
}
vis[x][now][flag]=ans;
// printf("x = %d now = %d flag = %d = %d\n",x,now,flag,ans);
return ans;
} void find_cnt()
{
for(int i=;i<=m;i++) cnt[i][]=cnt[i][]=bit[m];
for(int i=m;i>=;i--)
{
if(d[i]==)
{
for(int j=i-;j>=;j--)
{
cnt[j][]=ad(cnt[j][],-bit[i-]);
cnt[j][]=ad(cnt[j][],-bit[i-]);
}
cnt[i][]=ad(cnt[i][],-bit[i]);
for(int j=i+;j<=m;j++)
{
cnt[j][d[j]]=ad(cnt[j][d[j]],-bit[i]);
}
}
} } int dfs(int x,int now1,int now2,int flag1,int flag2)
{
if(x==) return ; if(f[x][now1][now2][flag1][flag2]!=-) return f[x][now1][now2][flag1][flag2];
LL ans=,now=;
int mx1=;if(flag1 || (x-==)) mx1=d[x-];
int mx2=;if(flag2 || (x-==)) mx2=d[x-];
if(now1+now2==) ans=ad(ans,(vis[x][now1][flag1]*bit[x])%mod);
for(int i=;i<=mx1;i++)
{
if(flag2 && (i^)>mx2)
{
int f1=flag1&(i==d[x-]);
int f2=flag2&(==d[x-]);
ans=ad(ans,dfs(x-,i,,f1,f2));
}
else
{
int f1=flag1&(i==d[x-]);
int f2=flag2&((i^)==d[x-]);
ans=ad(ans,dfs(x-,i,i^,f1,f2));
}
}
f[x][now1][now2][flag1][flag2]=ans;
// printf("f x = %d now1 = %d now2 = %d flag1 = %d flag2 = %d ans = %d\n",x,now1,now2,flag1,flag2,ans);
return ans;
} int DFS(int x,int now,int flag)
{
if(x==) return ;
if(g[x][now][flag]!=-) return g[x][now][flag];
int mx=;if(flag || (x-==)) mx=d[x-];
LL ans=;
ans=ad(ans,(((vis[x][now][flag]*cnt[x][now^])%mod)*bit[x])%mod);
for(int i=;i<=mx;i++)
{
ans=ad(ans,DFS(x-,i,flag&(i==d[x-])));
}
g[x][now][flag]=ans;
// printf("g x = %d now = %d flag = %d = %d\n",x,now,flag,ans);
return ans;
} LL quickpow(LL x,LL y)
{
LL ans=;
while(y)
{
if(y&) ans=(ans*x)%mod;
x=(x*x)%mod;
y/=;
}
return ans;
} int main()
{
freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
// freopen("news.in","r",stdin);
// freopen("news.out","w",stdout);
scanf("%lld%lld",&n,&p);
LL x=n-;m=;
memset(d,,sizeof(d));
while(x)
{
d[++m]=x%;
x/=;
}
bit[]=;
for(int i=;i<=;i++) bit[i]=(bit[i-]*)%mod;
memset(cnt,,sizeof(cnt));
memset(vis,-,sizeof(vis));
memset(f,-,sizeof(f));
memset(g,-,sizeof(g));
find_vis(m+,,);
find_cnt(); LL a1=dfs(m+,,,,);
LL a2=DFS(m+,,);
LL bn=quickpow(n%mod,mod-);
LL bb=quickpow(,mod-);
LL ans=; // for(int i=1;i<=3;i++)
// for(int j=0;j<=1;j++)
// printf("cnt %d %d = %I64d\n",i,j,cnt[i][j]); ans=ad(ans,(((a1*bn)%mod)*((p*bb)%mod))%mod);
ans=ad(ans,(((((a2*bn)%mod)*bn)%mod)*(((-p)*bb)%mod))%mod);
// printf("a1=%I64d a2=%I64d\n",a1,a2);
printf("%lld\n",ans);
return ;
}
x表示当前填到哪一位。flag表示当前是否和边界重合。
dfs是做加密的情况,也就是确定当前填的x,然后让跟它异或的y尽量大。
DFS是做不加密的情况,也就是确定当前填的x,然后y所有可能都算上。
其中vis是维护到当前状态的方案数。
cnt是表示当前某个数位上是0或1的方案数。
好了还是这种做法太复杂了。。
学习了一下出题人的做法。
出题人题解:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std; typedef long long LL;
const LL mod=;
const int N=;
LL n,m,p,bit[N],f[N][][],g[N][][];
int a[N]; LL quickpow(LL x,LL y)
{
LL ans=;
while(y)
{
if(y&) ans=(ans*x)%mod;
x=(x*x)%mod;
y/=;
}
return ans;
} void dp_1()
{
memset(f,,sizeof(f));
memset(g,,sizeof(g));
g[][][]=;
int now1,now2;
for(int i=;i<m;i++)
for(int x1=;x1<=;x1++)
for(int x2=;x2<=;x2++)
{
if(g[i][x1][x2]==) continue;
for(int j=;j<=;j++)
{
int k=j^;
if(j>a[i+] && x1) continue;
if(j==a[i+] && x1) now1=;
else now1=;
if(k>a[i+] && x2) k=;
if(k==a[i+] && x2) now2=;
else now2=;
g[i+][now1][now2]=(g[i+][now1][now2]+g[i][x1][x2])%mod;
f[i+][now1][now2]=(f[i+][now1][now2]+f[i][x1][x2]+((g[i][x1][x2]*(j^k))%mod*bit[i+])%mod)%mod;
}
}
} void dp_2()
{
memset(f,,sizeof(f));
memset(g,,sizeof(g));
g[][][]=;
int now1,now2;
for(int i=;i<m;i++)
for(int x1=;x1<=;x1++)
for(int x2=;x2<=;x2++)
{
if(g[i][x1][x2]==) continue;
for(int j=;j<=;j++)
{
if(j>a[i+] && x1) continue;
if(x1 && j==a[i+]) now1=;
else now1=;
for(int k=;k<=;k++)
{
if(k>a[i+] && x2) continue;
if(x2 && k==a[i+]) now2=;
else now2=;
g[i+][now1][now2]=(g[i+][now1][now2]+g[i][x1][x2])%mod;
f[i+][now1][now2]=(f[i+][now1][now2]+f[i][x1][x2]+(g[i][x1][x2]*(j^k))%mod*bit[i+]%mod)%mod;
}
}
}
} int main()
{
freopen("a.in","r",stdin);
// freopen("news.in","r",stdin);
// freopen("news.out","w",stdout);
scanf("%lld%lld",&n,&p);
LL x=n-,a1=,a2=;m=;
while(x)
{
a[++m]=x%;
x/=;
}
for(int i=;i<=m/;i++) swap(a[i],a[m-i+]);
bit[m]=;
for(int i=m-;i>=;i--) bit[i]=(bit[i+]*)%mod;
// for(int i=1;i<=m;i++) printf("%d ",a[i]);printf("\n"); dp_1();
for(int i=;i<=;i++)
for(int j=;j<=;j++)
a1=(a1+f[m][i][j])%mod;
dp_2();
for(int i=;i<=;i++)
for(int j=;j<=;j++)
a2=(a2+f[m][i][j])%mod; LL bn=quickpow(n%mod,mod-);
LL bb=quickpow(,mod-);
LL ans=; ans=(ans+((a1*bn%mod)*(p*bb%mod))%mod)%mod;
ans=(ans+((((a2*bn%mod)*bn)%mod)*((-p)*bb%mod))%mod)%mod;
// printf("a1=%I64d a2=%I64d\n",a1,a2);
printf("%lld\n",ans); return ;
}
第三题:
3653: 谈笑风生
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 689 Solved: 264
[Submit][Status][Discuss]
Description
设T 为一棵有根树,我们做如下的定义:
• 设a和b为T 中的两个不同节点。如果a是b的祖先,那么称“a比b不知道
高明到哪里去了”。
• 设a 和 b 为 T 中的两个不同节点。如果 a 与 b 在树上的距离不超过某个给定
常数x,那么称“a 与b 谈笑风生”。
给定一棵n个节点的有根树T,节点的编号为1 到 n,根节点为1号节点。你需
要回答q 个询问,询问给定两个整数p和k,问有多少个有序三元组(a;b;c)满足:
1. a、b和 c为 T 中三个不同的点,且 a为p 号节点;
2. a和b 都比 c不知道高明到哪里去了;
3. a和b 谈笑风生。这里谈笑风生中的常数为给定的 k。
Input
输入文件的第一行含有两个正整数n和q,分别代表有根树的点数与询问的个数。接下来n - 1行,每行描述一条树上的边。每行含有两个整数u和v,代表在节点u和v之间有一条边。
接下来q行,每行描述一个操作。第i行含有两个整数,分别表示第i个询问的p和k。
Output
输出 q 行,每行对应一个询问,代表询问的答案。
Sample Input
1 2
1 3
2 4
4 5
2 2
4 1
2 3
Sample Output
1
3
HINT
1<=P<=N
1<=K<=N
N<=300000
Q<=300000

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std; typedef long long LL;
const int N=*,M=*;
// const int N=2*300000,M=30*300000;
struct node{
int x,y,next;
}a[N];
struct trnode{
int lc,rc;
LL sum;
}t[M];
int n,m,num,len,tl;
int first[N],dfn[N],edfn[N],dep[N],tot[N],root[N]; int minn(int x,int y){return x<y ? x:y;} void ins(int x,int y)
{
a[++len].x=x;a[len].y=y;
a[len].next=first[x];first[x]=len;
} int add(int rt,int x,int d)
{
int now=++tl,tmp=now;
int l=,r=n,mid;
while(l<r)
{
mid=(l+r)/;
if(x<=mid)
{
r=mid;
t[now].lc=++tl;
t[tl].lc=t[tl].rc=;
t[now].rc=t[rt].rc;
rt=t[rt].lc;
now=tl;
}
else
{
l=mid+;
t[now].lc=t[rt].lc;
t[now].rc=++tl;
t[tl].lc=t[tl].rc=;
rt=t[rt].rc;
now=tl;
}
t[now].sum=t[rt].sum+d;
}
return tmp;
} LL query(int lx,int rx,int ql,int qr,int l,int r)
{
if(ql==l && qr==r) return t[rx].sum-t[lx].sum;//debug 一开始更新到了叶子节点。。
int mid=(l+r)/;
if(qr<=mid) return query(t[lx].lc,t[rx].lc,ql,qr,l,mid);
if(ql>mid) return query(t[lx].rc,t[rx].rc,ql,qr,mid+,r);
return query(t[lx].lc,t[rx].lc,ql,mid,l,mid)+query(t[lx].rc,t[rx].rc,mid+,qr,mid+,r);
} void dfs(int x,int fa)
{
dep[x]=dep[fa]+;
dfn[x]=++num;
tot[x]=;
for(int i=first[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==fa) continue;
dfs(y,x);
tot[x]+=tot[y];
}
edfn[x]=num;
} void build_tree(int x,int fa)
{
root[dfn[x]]=add(root[dfn[x]-],dep[x],tot[x]-);
for(int i=first[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==fa) continue;
build_tree(y,x);
}
} void output(int x,int l,int r)
{
printf("x = %d l = %d r = %d lc = %d rc = %d sum = %d\n",x,l,r,t[x].lc,t[x].rc,t[x].sum);
int mid=(l+r)/;
if(t[x].lc) output(t[x].lc,l,mid);
if(t[x].rc) output(t[x].rc,mid+,r);
} int main()
{
// freopen("a.in","r",stdin);
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%d%d",&n,&m);
num=;tl=;len=;
memset(first,,sizeof(first));
for(int i=;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ins(x,y);
ins(y,x);
}
dfs(,);
root[]=;t[].lc=t[].rc=;
build_tree(,);
LL ans;int p,k;
for(int i=;i<=m;i++)
{
scanf("%d%d",&p,&k);
ans=((LL)minn(dep[p]-,k))*((LL)(tot[p]-));
ans+=query(root[dfn[p]],root[edfn[p]],minn(n,dep[p]+),minn(n,dep[p]+k),,n);
printf("%lld\n",ans);
}
return ;
}
【20151105noip膜你赛】bzoj3652 bzoj3653的更多相关文章
- cdcqの省选膜你赛
cdcqの省选膜你赛 比赛当天因为在杠hnoi2016的大数据结构没有参加,今天补了一下.挺好玩的虽然不看一句话题意的话真的卡读题 此生无悔入东方,来世愿生幻想乡 2651. 新史「新幻想史 -现代史 ...
- 【良心noip膜你赛】总结
一点都不良心!!!! AK 快乐爆零快乐!!! 1. A. value512mb 1s规定一个区间的价值为这个区间中所有数 and 起来的值与这个区间所有数 or 起来的值的乘积.例如 3 个数 2, ...
- 2016-5-19模拟测试 bzoj3652 bzoj3653 bzoj3654
T1 description 给定正整数\(n\),定义\(f(x) = \max{y \ \mathrm{xor}\ x}(y<n)\) \(x\)在\([0,n)\)随机取值,求\(f(x) ...
- EZ 2018 1 21 2018noip第五次膜你赛
这次分数普遍偏高,而且yu'ben'ao又AK了! 但是最后一题莫名爆0让我很感伤啊(搓了1个多小时的20分暴力)! 难度偏低,主要是T2没剪枝,炸了3个点. T1 这种SB题恐怕是千年难遇了,PJ- ...
- EZ 2018 01 14 2018noip第四次膜你赛
这次惨烈的炸了个精光(只有20),然后对我的OI想法造成了巨大的转折. (以上有点作,其实我只是再也不用vector存图了而已(用邻接表)) 难度很不均匀,而且题型很狗(还有结论题???) T1 坑人 ...
- EZ 2017 12 30 2018noip第二次膜你赛
去年的比赛了,然而今天才改好. 总体难度适中,有大佬AK. 主要是自己SB第二题没想出来,然后又是可怜的100来分. T1 一道二分+数学的题目. 我们可以二分叫的次数,然后用公式(等差数列,公差都是 ...
- EZ 2017 12 17初二初三第一次膜你赛
以后平时练习还是写一写吧. (题目搞来搞去太烦了,直接PDF存起来) T1 水题(???),主要是数据水,正解是设一个阙值,然而根本没人打.(暴力出奇迹) CODE #include<cstdi ...
- [SinGuLaRiTy] NOIP 膜你赛-Day 2
[SinGuLaRiTy-1031] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 对于所有题目: Time Limit: 1s | Mem ...
- [SinGuLaRiTy] NOIP膜你赛-Day 1
[SinGuLRiTy-1022] Copyright (c) SinGuLaRITy 2017. All Rights Reserved. 对于所有题目:Time Limit:1s || Memo ...
随机推荐
- No Route to Host from master/192.168.2.131 to master:9000 failed on socket t
host里边添加的ip地址与当前的ip地址(ifconfig可以查看)不一致,修改当前ip地址就可以了.
- java — 线程池
线程池的作用 线程池作用就是限制系统中执行线程的数量. 根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果:少了浪费了系统资源,多了造成系统拥挤效率不高.用线程池控 ...
- iOS-开发过程中应用间跳转问题
- iOS中UIButton控件的用法及部分参数解释
在UI控件中UIButton是极其常用的一类控件,它的类对象创建与大多数UI控件使用实例方法init创建不同,通常使用类方法创建: + (id)buttonWithType:(UIButtonType ...
- <Effective C++>读书摘要--Resource Management<二>
<Item 15> Provide access to raw resources in resource-managing classes 1.You need a way to con ...
- JAVA学习之泛型
ArrayList<E>类定义和ArrayList<Integer>类引用中涉及的术语:1.整个ArrayList<E>称为泛型类型 2.ArrayList< ...
- [计算机网络-应用层] FTP协议
文件传输协议:FTP 如下图所示:用户通过一个FTP用户代理与FTP交互.该用户首先提供远程主机的主机名,使本地主机的FTP客户机进程建立一个到远程主机FTP服务器进程的TCP连接.然后,该用户提供用 ...
- python将字符串转换成字典的几种方法
当我们遇到类似于{‘a’:1, 'b':2, 'c':3}这种字符串时,想要把它转换成字典进行处理,可以使用以下几种方法: 1. Python自带的eval函数(不安全) dictstr = '{&q ...
- 【转】Unity+单例模式的依赖注入
http://www.cnblogs.com/floyd/archive/2009/06/17/1505117.html
- POJ1236:Network of Schools——题解
http://poj.org/problem?id=1236 首先还是缩点,然后入度为0的点的个数就是你要投文件个数. 然后我们对于入度和出度为0的点的个数取最大值即为答案. (简单证明:入度和出度为 ...