【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 ...
随机推荐
- C++第一次课堂作业 circle
Github上的代码提交
- TCP系列24—重传—14、F-RTO虚假重传探测
一.虚假重传 在一些情况下,TCP可能会在没有数据丢失的情况下初始化一个重传,这种重传就叫做虚假重传(Spurious retransmission).发生虚假重传的原因可能是包传输中重排序.传输中发 ...
- django使用ajax提交表单数据报403错解决方法
只需要在.ajaxSetup方法中设置csrfmiddlewaretoken即可 $.ajaxSetup({ data: {csrfmiddlewaretoken: '{{ csrf_token }} ...
- HTML5拖拽表格中单元格间的数据库
效果图:
- table 标签 语法
- 【Todo】【转载】JVM学习
先参考如下这个系列<聊聊JVM> http://blog.csdn.net/column/details/talk-about-jvm.html
- (转)python 搭建libsvm方法。python版本和libsvm版本匹配很重要!
<集体智慧编程>关于婚介数据集的SVM分类 转自:http://muilpin.blog.163.com/blog/static/165382936201131875249123/ 作 ...
- CentOS 查看系统内核和版本
1.uname 命令用于查看系统内核与系统版本等信息,格式为“uname [-a]”. [root@bigdata-senior01 ~]# uname -a Linux bigdata-senior ...
- 2017 ICPC beijing F - Secret Poems
#1632 : Secret Poems 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 The Yongzheng Emperor (13 December 1678 – ...
- 用Docker搭建Nexus私服
搜索Nexus 在docker容器中加载Nexus镜像 发布本地项目到Nexus私服 配置连接方式 发布指令 打源码包上传插件 搜索Nexus 在我们打算使用Nexus时,我们先搜索一下docke ...