【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 ...
随机推荐
- oracle数据库之游标的使用
一.游标概念 为了处理 SQL 语句,ORACLE 必须分配一片叫上下文( context area )的区域来处理所必需的信息,其中包括要处理的行的数目,一个指向语句被分析以后的表示形式的指针以及查 ...
- AWVS使用基础教程
什么是AWVS Acunetix Web Vulnerability Scanner(简称AWVS)是一款知名的网络漏洞扫描工具,它通过网络爬虫测试你的网站安全,检测流行安全漏洞,现已更新到10.(下 ...
- deep learning3
9.3.Restricted Boltzmann Machine (RBM)受限玻尔兹曼基 假设有一个二部图,每一层的节点之间没有链接,一层是可视层,即输入数据层(v),一层是隐藏层(h),如果假设所 ...
- HUAS 1483 mex(莫队算法)
考虑莫队算法,对于区间减小的情况,可以O(1)解决.对于区间增加的情况,可能需要O(n)解决.好在数据不卡莫队. 1200ms过了. 离线+线段树 760ms过了. # include <cst ...
- vijos1859[TJOI2014]电源插排
题意:小 M 的实验室有很多电源插排.这些插排的编号从 1 到 N,由左向右排成一排.每天早晨,这些插排都是没有被使用的.每当一个学生来到实验室,他就将自己的笔记本电源插到某一个未被使用的插排上.实验 ...
- 【bzoj4579】[Usaco2016 Open]Closing the Farm 并查集
题目描述 Farmer John and his cows are planning to leave town for a long vacation, and so FJ wants to tem ...
- 【bzoj4698】[Sdoi2008] Sandy的卡片 后缀数组
题目描述 Sandy和Sue的热衷于收集干脆面中的卡片.然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型.每一张卡片都由一些数字进行标记,第i张卡片的序列 ...
- Codeforces Round#516 Div.1 翻车记
A:开场懵逼.然后发现有人1min过,于是就sort了一下,于是就过了.正经证明的话,考虑回文串两端点一定是相同的,所以最多有Σcnti*(cnti+1)/2个,cnti为第i种字母出现次数.而sor ...
- Give NetScaler a “Tune-Up”
Give NetScaler a “Tune-Up” https://www.citrix.com/blogs/2014/10/21/give-netscaler-a-tune-up/ To Opti ...
- Android Bitmap和Drawable互转及使用BitmapFactory解析图片流
一.Bitmap转Drawable Bitmap bmp=xxx; BitmapDrawable bd=new BitmapDrawable(bmp); 因为BtimapDrawable是Drawab ...