2017 多校 3(6056-6066)进度(5/11)
来源:互联网 发布:数据分析师证书难不难 编辑:程序博客网 时间:2024/05/01 09:40
A - simple counting problem HDU - 6056
待补
B - Kanade’s convolution HDU - 6057
待补
C - Kanade’s sum HDU - 6058 (模拟队列/链表)
题意:给n个数是(1-n),然后问所有序列中第k大的数之和是多少。
当时和队友先找规律找半天,然后觉得不对。之后就怎么想都超时。
赛后看到有人模拟做的,自己先模拟了一下,还是超时,直接模拟太暴力了。从第一个数开始考虑,当这个数是第k大的时候,先找左边它大的,找到k-1个,然后往左边找。注意一下边界。。
我的是左边来一下,右边来一下,肯定超时啦。。
第二种方法是用链表,从小到大扫,然后扫完之后删除节点就行了。直接记录位置,扫的当前点,与它相连的都是比它大的,不用扫比它小的了,因为比它小的已经删除了。
//直接模拟(TIME:1934ms)差一点就超时了//用c++交会tle ,用G++交
#include <iostream>#include <cstring>#include <algorithm>#include <cmath>#include <cstdio>using namespace std;#define LL long longconst int maxn = 1000020;LL a[maxn];int b[maxn];int main(){ int T; scanf("%d",&T); while(T--) { int n,k; scanf("%d %d",&n,&k); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); LL ans=0; for(int i=1;i<=n;i++) { int h=0; b[++h]=i; int j; for(j=i+1;j<=n&&h<k;j++) { if(a[j]>a[i]) b[++h]=j; } if(h>=k) { LL temp=1,t=0; for(;j<=n;j++) { if(a[j]>a[i]) break; else temp++; } t+=temp; for(j=i-1;j>=1;j--) { if(a[j]>a[i]&&h<=1) break; else if(a[j]>a[i]) { temp=b[h]-b[h-1]; h--; t+=temp; } else t+=temp; } ans+=t*a[i]; } else { int g=h; for(j=i-1;j>=1;j--) { if(a[j]>a[i]) b[++g]=j; if(g==k) break; } if(g<k) continue; int temp=n-b[h]+1,t=temp; for(j=j-1;j>=1;j--)//这里为j-1//因为这个WA了好多次 { if(a[j]>a[i]) { if(h<=1) break; temp=b[h]-b[h-1]; h--; t+=temp; } else t+=temp; } ans+=t*a[i]; } } printf("%lld\n",ans); } return 0;}
//链表//(TIME:546ms)
#include <iostream>#include <cstring>#include <algorithm>#include <cmath>#include <cstdio>using namespace std;#define LL long longconst int maxn = 5e5+10;int pre[maxn],nxt[maxn],pos[maxn];int r[maxn],l[maxn];int main(){ int T; scanf("%d",&T); while(T--) { int n,k; scanf("%d %d",&n,&k); for(int i=1;i<=n;i++) { int x; scanf("%d",&x); pos[x]=i; pre[pos[x]]=i-1; nxt[pos[x]]=i+1; } LL ans=0; for(int i=1;i<=n;i++) { int now=pos[i],right=0,left=0; for(int j=now;j<=n&&right<k;j=nxt[j]) { r[right++]=nxt[j]-j; } LL num=0; for(int j=now;j>=1&&left<k;j=pre[j]) { if(left+right>=k){ l[left]=j-pre[j]; num+=l[left]*r[k-left-1]; left++; } else { left++; continue; } } ans+=(LL)num*i; nxt[pre[pos[i]]]=nxt[pos[i]]; pre[nxt[pos[i]]]=pre[pos[i]]; } printf("%lld\n",ans); } return 0;}
D - Kanade’s trio HDU - 6059 (01字典树)
题意:给你一个数组A[n]下标从1开始到n,问有多少个三元组(i,j,k),i < j < k,使得(A[i]^A[j])<(A[j]^A[k])
第一反应是枚举j,然后j的前面都放在一个字典树Trie1中,j的后面后放在一个字典树Trie2中。然后发现没有办法去统计个数。了别人题解之后知道了~~ 满足条件的三元组,如果A[i],A[k]的前10位都相同,第11位不同了
第11位,A[i]=0,A[k]=1,那么A[j]=0,之后的值都可以任意取了。
A[i]=1,A[k]=0,那么A[j]=1,之后的值也可以任意取了。
所以我们用找A[i],A[k]第一个不同的位置,然后统计有多少那个j就行了。
dalao的思路:先从小到大枚举k,把A[k]一个一个插入字典树中,然后相应位统计有多少个j。这样就保证了j < k
然后从小到大枚举i,将以i作为k的对应位数有多少个j减去,这样就保证了i < k.(相当于k的范围在(i,k] ),现在j的范围是[1,k),对于当前i,相应位的j我们要减去i出现的次数就可以保证i
#include <iostream>#include <cstring>#include <cstdio>#include <cmath>#include <algorithm>using namespace std;#define LL long longconst int maxn = 500005;int a[maxn];int node[maxn*10][2];LL val[maxn*10][2];LL num[32][2];LL coun[maxn*10][2];int tot=1;void sert(int x,int d){ int u=0; for(int i=30;i>=0;i--) { int g=(x>>i)&1; if(!node[u][g]) { node[u][g]=tot++; } coun[u][g]+=d*num[i][1-g];//如果这里是num[u][1-g]的话,会TLE,因为这样的话num的空间就比较大了,memset就比较耗时. val[u][g]+=d; num[i][g]++; u=node[u][g]; }}LL lookf(int x){ LL sum=0; int u=0; for(int i=30;i>=0;i--) { int g1=(x>>i)&1; if(node[u][1-g1]) sum+=coun[u][1-g1]-(LL)val[u][1-g1]*num[i][g1];//这里要防止爆int u=node[u][g1]; } return sum;}int main(){ int T; scanf("%d",&T); while(T--) { tot=1; memset(val,0,sizeof(val)); memset(node,0,sizeof(node)); memset(num,0,sizeof(num)); memset(coun,0,sizeof(coun)); memset(a,0,sizeof(a)); int n; scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%d",&a[i]); sert(a[i],1); } LL ans=0; memset(num,0,sizeof(num)); for(int i=0;i<n;i++) { sert(a[i],-1); ans+=lookf(a[i]); } printf("%I64d\n",ans); } return 0;}
思考:num[i][g]表示第i位上为g的个数,那么我计算j的时候应该会有重复的值。之后好像又减去了。。这一点还没怎么明白== (望路过的dalao们指点指点
感觉还是用指针写比较清楚点
#include <iostream>#include <cstring>#include <cstdio>#include <cmath>#include <algorithm>using namespace std;#define LL long longconst int maxn = 500005;int a[maxn];struct Node{ Node *son[2]; int coun; int val; node(){ coun=0,val=0;son[0]=son[1]=NULL; }};Node *root;int node[maxn*10][2];LL val[maxn*10][2];LL num[32][2];LL coun[maxn*10][2];int tot=1;void sert(int x,int d){ Node *u=root; for(int i=30;i>=0;i--) { int g=(x>>i)&1; if(u->son[g]==NULL) { u->son[g]=new Node(); } u=u->son[g]; u->coun+=d*num[i][1-g]; u->val+=d; num[i][g]++; }}LL lookf(int x){ LL sum=0; Node *u=root; for(int i=30;i>=0;i--) { int g1=(x>>i)&1; Node *p=u->son[1-g1]; //if(!val[u][g1]) break; if(p) sum+=p->coun-(LL)p->val*num[i][g1]; u=u->son[g1]; if(u==NULL) break; } return sum;}int main(){ int T; scanf("%d",&T); while(T--) { root=new Node(); int n; memset(num,0,sizeof(num)); scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%d",&a[i]); sert(a[i],1); } LL ans=0; memset(num,0,sizeof(num)); for(int i=0;i<n-2;i++) { sert(a[i],-1); ans+=lookf(a[i]); } printf("%lld\n",ans); } return 0;}
E - RXD and dividing (贪心+dfs)
题意:给你一棵树,将除1之外的点分成k份,每份使之连通(会加一些边),边权之和最大为多少。
很巧妙。这个就是要算每条边的最大贡献。假 设x是根,有y个孩子(所有孩子,孩子的孩子也算),这个时候上面的那条边v的贡献为v*min(y+1,k)因为自己也要算
#include <iostream>#include <cstring>#include <algorithm>#include <cmath>#include <cstdio>#include <vector>using namespace std;#define LL long longconst int maxn = 1e6+10;struct node{ int to; LL v; node(int a=0,LL b=0){ to=a,v=b; }};vector<node> vec[maxn];int vis[maxn];void addedge(int from,int to,LL v){ vec[from].push_back(node(to,v)); vec[to].push_back(node(from,v));}LL ans=0;int n,k;int dfs(int pos,LL zz){ int hz=0; for(int i=0;i<vec[pos].size();i++) { node e=vec[pos][i]; if(!vis[e.to]) { hz++; vis[e.to]=1; hz=hz+dfs(e.to,e.v); } if(i==vec[pos].size()-1){ int b=hz+1; LL g=min(k,b); ans+=g*zz; } } return hz;}void init(){ memset(vis,0,sizeof(vis)); for(int i=0;i<maxn;i++) vec[i].clear();}int main(){ while(scanf("%d %d",&n,&k)!=EOF) { init(); for(int i=1;i<n;i++) { int from,to;LL v; scanf("%d %d %I64d",&from,&to,&v); addedge(from,to,v); } ans=0; vis[1]=1; dfs(1,0); printf("%I64d\n",ans); } return 0;}
F - RXD and functions HDU - 6061 (快速数论变换(NTT))
待补
G - RXD and logic gates HDU - 6062
待补
H - RXD and math HDU - 6063 (思维+快速幂)
开始还以为和莫比乌斯反演有关,然后开始推,推半天。然后想打个表看看,结果发现了规律,答案就是n^k%mod,快速幂搞一下就行了。
I - RXD and numbers HDU - 6064
待补
J - RXD, tree and sequence HDU - 6065 (决策单调性优化DP)
待补
K 签到
- 2017 多校 3(6056-6066)进度(5/11)
- 我来更新下进度(3)
- 学习操作系统的进度(3)
- 项目进度(二)
- 项目进度(三)
- 项目进度(四)
- 项目进度(五)
- 项目进度(六)
- 项目进度(七)
- 项目进度(八)
- 项目进度(九)
- 项目进度(十)
- 项目进度(十一)
- 项目进度(十二)
- MSN 研究进度 (一)
- 引擎开发进度(二)
- 引擎开发进度(三)
- 引擎开发进度(四)
- ubuntu 16.04服务器nginx+mysql+php5.6+sftp配置
- 料理材料
- C++中的static
- Python中的相对文件路径的调用
- JS类型转换
- 2017 多校 3(6056-6066)进度(5/11)
- CI中的load理解
- 「网络流 24 题」分配问题
- Android护眼模式功能小记
- HDU-6055-Regular polygon
- goolge浏览器插件
- (HDU
- POST解析(Imagerloader、异步、图片、文字、listv显示)
- View事件传递