2015 ACM/ICPC Asia Regional Changchun Online
来源:互联网 发布:sgd算法 矩阵分解 编辑:程序博客网 时间:2024/04/30 11:01
更新中.......
<题目链接>
A.Alisha's Party (模拟+优先队列)
题意:Alisha 他邀请了她的朋友参加她的生日party,每个朋友将会给她带一份礼物。由于她的院子不够大,每次他的某个朋友来了之后她就会开门同时放p个人进来(假如外面没有p个人,就把外面的所有人放进来),进来的顺序按礼物的价值由搞到低进,价值相同的则按来的先后顺序进。当最后一个朋友来了之后,就会将所有没有进来的人全部放进去。现在问你q次,每次问你第x个进来的人是谁。
分析:用优先队列直接模拟就好了。注意最后要把所有的人放进来。
代码:
#include <bits/stdc++.h>using namespace std;typedef long long LL;typedef unsigned long long ULL;const LL INF = 1E9+9;const int maxn = 2e5+6;struct node{ int v,id; bool operator < (const node & t)const { if(v!=t.v) return v<t.v; return id>t.id; }}s[maxn];char name[maxn][202];pair <int ,int > p[maxn];priority_queue <node > que;int ans[maxn];int main(){ int ncase,n,k,m,i,j,x,y,q; scanf("%d",&ncase); while(ncase--) { scanf("%d%d%d",&k,&m,&q); for(i=1;i<=k;i++) { scanf("%s%d",name[i],&s[i].v); s[i].id=i; } for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); p[i]=make_pair(x,y); } sort(p+1,p+m+1); int cur=1,cnt=1,num=0; for(i=1;i<=m;i++) { while(cur<=k && cur<=p[i].first) que.push(s[cur++]); num=p[i].second; while(num-- && !que.empty()) { ans[cnt++]=que.top().id; que.pop(); } } while(cur<=k) que.push(s[cur++]); while(!que.empty()) { ans[cnt++]=que.top().id; que.pop(); } scanf("%d",&x); printf("%s",name[ans[x]]); for(i=2;i<=q;i++) { scanf("%d",&x); printf(" %s",name[ans[x]]); } printf("\n"); } return 0;}
B.Ponds(并查集)
题意:给定一个图,将图中所有度小于2的顶点去掉,知道图里面没有度小于2的顶点为止。求剩余的顶点的权值之和(注意题目要求剩余顶点所在的子图里面顶点数目为odd)。
分析:类似拓扑排序,每次去掉度为1的顶点,同时更新并查集。
代码:
#include <bits/stdc++.h>using namespace std;typedef long long LL;typedef unsigned long long ULL;const LL INF = 1E9+9;const int maxn = 2e5+6;struct node{ int v,id; bool operator < (const node & t)const { if(v!=t.v) return v<t.v; return id>t.id; }}s[maxn];char name[maxn][202];pair <int ,int > p[maxn];priority_queue <node > que;int ans[maxn];int main(){ int ncase,n,k,m,i,j,x,y,q; scanf("%d",&ncase); while(ncase--) { scanf("%d%d%d",&k,&m,&q); for(i=1;i<=k;i++) { scanf("%s%d",name[i],&s[i].v); s[i].id=i; } for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); p[i]=make_pair(x,y); } sort(p+1,p+m+1); int cur=1,cnt=1,num=0; for(i=1;i<=m;i++) { while(cur<=k && cur<=p[i].first) que.push(s[cur++]); num=p[i].second; while(num-- && !que.empty()) { ans[cnt++]=que.top().id; que.pop(); } } while(cur<=k) que.push(s[cur++]); while(!que.empty()) { ans[cnt++]=que.top().id; que.pop(); } scanf("%d",&x); printf("%s",name[ans[x]]); for(i=2;i<=q;i++) { scanf("%d",&x); printf(" %s",name[ans[x]]); } printf("\n"); } return 0;}
C.Aggregated Counting (OEIS+离线处理)
题意:给定序列a[1...oo]=1、2、2、3、3、4、4、4.......规律是加a[cur]个cur(cur表示当前值的大小)。比如再往后接,就是接3个5,再接4个6......,给定整数n,最后一个n的位置p1,最后一个p1的位置p2,求p2。比如n=3,最后一个3的位置是5,最后一个5的位置是11,那么答案就是11。
分析:先写个暴力版本的,把前面的几个数丢到OEIS.......发现有公式!!!公式:sigma{i*a[i],1<=i<=n},将和式压缩求解,比如n=3,ans=1*1+(2+3)*2。但是,复杂度为q*sqrt(n),数据比较多,发现计算小的对大的数有帮助,离线处理就好了。
代码:
#include <bits/stdc++.h>using namespace std;typedef long long LL;typedef unsigned long long ULL;const LL INF = 1E9+9;const int maxn = 1e6+6;const LL mod = 1000000007;int a[maxn],cur;struct node{ int id,x; bool operator < (const node &t)const { return x<t.x; }}q[10000];LL ans[10000];void Init(){ cur=3; int p=4; a[1]=1; a[2]=2; a[3]=2; while(1) { for(int j=1;j<=a[cur] && p<maxn-1;j++) a[p++]=cur; cur++; if(p>=maxn-1) break; }}int Find(int x){ int pos1=lower_bound(a,a+maxn,x+1)-a-1; return lower_bound(a,a+maxn,pos1+1)-a-1;}inline LL cal(LL s,LL x){ return (s+s+x-1)*x/2%mod;}int getAns(int x){ LL cur=1,len=0,L=0; LL ret=0; while(L<x) { if(L+a[cur]<=x) { ret=(ret+cur*cal(L+1,a[cur])); if(ret>mod) ret%=mod; L+=a[cur]; cur++; } else { ret=(ret+cur*cal(L+1,x-L)); if(ret>mod) ret%=mod; L=x; } } //printf("cur:%lld \n",cur); return int(ret);}void getall(int n){ LL cur=1,L=0; LL ret=0; for(int i=0;i<n;i++) { while(L<q[i].x) { if(L+a[cur]<q[i].x) { ret=(ret+cur*cal(L+1,a[cur]))%mod; L+=a[cur]; cur++; } else { ans[q[i].id]=(ret+cur*cal(L+1,q[i].x-L))%mod; break; } } }}int main(){// freopen("test.txt","r",stdin);// freopen("h.txt","w",stdout); Init(); int ncase,x; scanf("%d",&ncase); for(int i=0;i<ncase;i++) { scanf("%d",&q[i].x); q[i].id=i; } sort(q,q+ncase); getall(ncase); for(int i=0;i<ncase;i++) printf("%lld\n",ans[i]); return 0;}
D.Clock Adjusting(待更新)
E.Travel(并查集+离线处理)
题意:给定一个图,有q次查询,每次查询给定一个整数x,问图里面有多少点对(u,v),(u,v)要满足:u<-->v这条路径上的相邻点的路径的权值不大于x。
分析;将边按权值由小到大排序。每查询一次,往图里面添加权值不大于x的边。每个子图就是一个集合,用并查集维护,动态更新答案。
代码:
#include <bits/stdc++.h>using namespace std;typedef long long LL;typedef unsigned long long ULL;const LL INF = 1E9+9;const int maxn = 2e5+6;int fa[maxn],sz[maxn];LL ans[maxn];struct node{ int a,b,v; bool operator < (const node &t)const { return v<t.v; }}s[maxn];struct que{ int id,x; bool operator < (const que &t)const { return x<t.x; }}query[maxn];int Find(int rt){ if(fa[rt]==rt) return rt; return fa[rt]=Find(fa[rt]);}inline LL cal(LL n){ if(n<2) return 0; return n*(n-1)>>1;}void Init(int lim){ for(int i=1;i<=lim;i++) { fa[i]=i; sz[i]=1; }}LL cur;void update(int a,int b){ int root1=Find(a),root2=Find(b); if(root1==root2) return ; cur-=cal(sz[root1])*2; cur-=cal(sz[root2])*2; fa[root1]=root2; sz[root2]+=sz[root1]; sz[root1]=0; cur+=cal(sz[root2])*2;}int main(){ int ncase,n,m,i,j,x,y,v,q; scanf("%d",&ncase); while(ncase--) { scanf("%d%d%d",&n,&m,&q); Init(n); for(i=1;i<=m;i++) scanf("%d%d%d",&s[i].a,&s[i].b,&s[i].v); sort(s+1,s+m+1); for(i=1;i<=q;i++) { scanf("%d",&query[i].x); query[i].id=i; } sort(query+1,query+q+1); j=1; cur=0; for(i=1;i<=q;i++) { for(;j<=m && s[j].v<=query[i].x;j++) update(s[j].a,s[j].b); ans[query[i].id]=cur; } for(i=1;i<=q;i++) printf("%lld\n",ans[i]); } return 0;}
F.Favorite Donut(后缀数组)
题意:给定长度为n的字符串s(s是环),然后以某一点顺时针或者逆时针出发遍历字符串s将得到一个t,求一个字典序最大的字符串t的起始位置。字典序相同的选起始位置靠前的,位置相同的选顺时针的。
分析:将原来的字符串添加字符,使得前n个字符,每个字符与其后面的n-1个字符正是循环遍历的字符串。比如aabca--->aabcaaabc (顺时针) aabca---->acbaaacba (逆时针),然后对新构造出来的字符串求其后缀数组,那么可以得到字典序最大的两个字符串(两个方向),把字符串取出来,然后比较一下就行了。
ps:对于顺时针的字符串末尾要加一个表示负无穷的字符。这样保证后缀suffix(i)与suffix(j)的LCP等于其中一个后缀的时候,位置靠前的优先选择。
对于逆时针的字符串末尾要加一个表示正无穷的字符。这样保证后缀suffix(i)与suffix(j)的LCP等于其中一个后缀的时候,位置靠后的优先选择。这里的靠后是反转之后的字符串,再反过来就是靠前的了。
代码:
#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <set>using namespace std;const int maxn = 1e5+6;char in[maxn],s[maxn];int sa[maxn],t[maxn],t2[maxn],c[maxn],n;void build_sa(int n,int m){int i,*x=t,*y=t2;for(i=0;i<m;i++)c[i]=0;for(i=0;i<n;i++)c[x[i]=s[i]]++;for(i=1;i<m;i++)c[i]+=c[i-1];for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;for(int k=1;k<=n;k<<=1){int p=0;for(i=n-k;i<n;i++)y[p++]=i;for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;for(i=0;i<m;i++)c[i]=0;for(i=0;i<n;i++)c[x[y[i]]]++;for(i=1;i<m;i++)c[i]+=c[i-1];for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];swap(x,y);p=1;x[sa[0]]=0;for(i=1;i<n;i++)x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;if(p>=n)break;m=p;}}void GetSuffix(char buf[],char str[],int p,int n){for(int cnt=0,i=p;cnt<n;cnt++,i++)buf[cnt]=str[i];buf[n]='\0';}char ts[maxn],s1[maxn],s2[maxn];int main(){int ncase,n,i,j,p1,p2,len1,len2;scanf("%d",&ncase);while(ncase--){scanf("%d%s",&n,in);strcpy(ts,in);for(i=0;i<n-1;i++)ts[n+i]=ts[i];ts[n+i]='\0';len1=strlen(ts);strcpy(s,ts);build_sa(len1+1,255);for(i=len1;i>=0 && sa[i]>=n;i--);p1=sa[i];GetSuffix(s1,ts,p1,n);strcpy(ts,in);reverse(ts,ts+n);for(i=0;i<n-1;i++)ts[n+i]=ts[i];ts[n+i]='\0';len2=strlen(ts);ts[len2]='z'+1;strcpy(s,ts);build_sa(len2+1,255);for(i=len2;i>=0 && sa[i]>=n;i--) ;p2=sa[i];GetSuffix(s2,ts,p2,n);//printf("%s\n%s\n",s1,s2);p1=p1+1;p2=n-p2;int temp=strcmp(s1,s2);if(temp!=0)temp==1?printf("%d 0\n",p1):printf("%d 1\n",p2);else if(p1!=p2)p1<p2?printf("%d 0\n",p1):printf("%d 1\n",p2);elseprintf("%d 0\n",p1);}return 0;}
G.The Water Problem (暴力)
题意:查询区间最大值,数据范围很小。
分析:直接暴力查询就好,比赛的时候没看数据范围,用的线段树。。。。。
代码:
#include <bits/stdc++.h>using namespace std;typedef long long LL;typedef unsigned long long ULL;const LL INF = 1E9+9;int a[1005];int main(){ int ncase; scanf("%d",&ncase); while(ncase--) { int n,q,i,j,m,l,r; scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i]); scanf("%d",&q); while(q--) { m=-(1<<30); scanf("%d%d",&l,&r); for(i=l;i<=r;i++) if(a[i]>m) m=a[i]; printf("%d\n",m); } } return 0;}
H. Elven Postman(二叉树)
题意:给定一棵排序二叉树的先序遍历,给定整数x,求从根节点到x的路径。
分析:暴力模拟。先把树建起来,然后由于是排序二叉树,直接走就行了。
代码:
#include <bits/stdc++.h>using namespace std;typedef long long LL;typedef unsigned long long ULL;const LL INF = 1E9+9;const int maxn = 1005;struct node{ int v; node *lson,*rson; node() { lson=rson=nullptr; } node(int x,node *l=nullptr,node *r=nullptr) :v(x),lson(l),rson(r) {}};int a[maxn];node* build(int x,int y){ if(x>y) return nullptr; if(x==y) return new node(a[x]); int cur=x+1; while(cur<=y && a[cur]<a[x]) cur++; node *L=build(x+1,cur-1); node *R=build(cur,y); return new node(a[x],L,R);}void check(node *root){ if(root!=nullptr) { check(root->lson); printf("%d ",root->v); check(root->rson); } }void print(node *root,int x){ if(x==root->v) return ; if(x<root->v) { putchar('E'); print(root->lson,x); } else { putchar('W'); print(root->rson,x); }}int main(){ int ncase,n,q,i,j,x; scanf("%d",&ncase); while(ncase--) { scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i]); node *root=build(1,n); scanf("%d",&q); while(q--) { scanf("%d",&x); if(root->v==x) { puts(""); continue ; } print(root,x); puts(""); } } return 0;}
I.Food Problem(待更新)
J.Unknow Treasure(lucas+crt)
题意:求C(n,m)%M,M<10^18。M=p1*p2.....pk,(1<=k<=10)and (pi<100 000,pi is s prime)。
分析:直接用lucas求出C(n,m)%pi的值,然后用中国剩余定理把这些值合并。可惜啊,模版题不会,要不然当时就出线了。
代码:
#include <bits/stdc++.h>using namespace std;typedef long long LL;typedef unsigned long long ULL;const int N =150000;LL fac[N];void init(LL p){ int i; fac[0] =1; for(i =1; i <= p; i++) fac[i] = fac[i-1]*i % p;}LL mul(LL a,LL b,LL p){ if(a==0 || b==0) return 0; int fg=1; if(a<0 && b<0) { a=-a; b=-b; } else if(a<0 || b<0) { if(a<0) a=-a; else b=-b; fg=-1; } LL ret(0); while(b) { if(b&1) ret=(ret+a)%p; a=(a<<1)%p; b>>=1; } return ret*fg;}LL myPow(LL a,LL n,LL p){ LL ret=1; while(n) { if(n&1) ret=mul(ret,a,p); n>>=1; a=mul(a,a,p); } return ret;}LL C(LL n,LL m,LL p){ if(m > n) return 0; return fac[n]*myPow(fac[m]*fac[n-m], p-2,p)%p;}LL Lucas(LL n, LL m,LL p){ if(m ==0) return 1; else return (C(n%p, m%p,p)*Lucas(n/p, m/p,p))%p;}LL r[100],mo[100];void gcd(LL a,LL b,LL &d,LL &x,LL &y){ if(!b) { d=a; x=1; y=0; return ; } gcd(b,a%b,d,y,x); y-=x*(a/b);}LL china(int n) //x=r[i] (mod m[i]){ LL M=1; LL i,Mi,x,y,d,ans=0; for(i=1;i<=n;i++) M*=mo[i]; for(i=1;i<=n;i++) { Mi=M/mo[i]; gcd(Mi,mo[i],d,x,y); //printf("%lld %lld %lld \n",Mi,x,r[i]); LL temp=mul(Mi,x,M); temp=mul(temp,r[i],M); ans=(ans+temp+M)%M; // ans=(ans+Mi*x*r[i])%M; } return (ans+M)%M;}int main(){ int t,k,i,j; scanf("%d",&t); while(t--) { LL n,m,p; scanf("%lld%lld%d",&n,&m,&k); for(i=1;i<=k;i++) { scanf("%lld",&p); init(p); r[i]=Lucas(n,m,p); mo[i]=p; } printf("%lld\n",china(k)); } return 0;}
K.Good Numbers(待更新)
L.Marisa's Cake(待更新)
M.Robot Dog(待更新)
- 2015 ACM/ICPC Asia Regional Changchun Online
- 2015 ACM/ICPC Asia Regional Changchun Online
- 2012 ACM/ICPC Asia Regional Changchun Online
- 2013 ACM/ICPC Asia Regional Changchun Online
- 2013 ACM/ICPC Asia Regional Changchun Online
- 2013 ACM/ICPC Asia Regional Changchun Online
- 2015 ACM/ICPC Asia Regional Changchun Online(1002)
- 2015长春网络赛 ACM/ICPC Asia Regional Changchun Online
- 2015 ACM/ICPC Asia Regional Changchun Online(1007)
- 2015 ACM/ICPC Asia Regional Changchun Online hdu 5438
- hdu5443(2015 ACM/ICPC Asia Regional Changchun Online )
- Alisha’s Party--2015 ACM/ICPC Asia Regional Changchun Online
- 【题解】 2015 ACM/ICPC Asia Regional Changchun Online (5+2)
- 2015 ACM/ICPC Asia Regional Changchun Online(1001)
- 2015 ACM/ICPC Asia Regional Changchun Online(1008)
- 2015 ACM/ICPC Asia Regional Changchun Online(1005)
- 2015 ACM/ICPC Asia Regional Changchun Online (部分)
- 2015 ACM/ICPC Asia Regional Changchun Online hdu5444
- 今天MATLAB2015B安装界面
- 51nod 1212 无向图最小生成树 (Kruskal)
- ios初次面试(20151023)
- Ubuntu更新命令
- git 命令备忘
- 2015 ACM/ICPC Asia Regional Changchun Online
- Nodejs网络模块的选择
- Leetcode -- Merge Intervals
- [48]Rotate Image
- mysql 导出 sql 执行sql
- iOS的常见问题---Object-C有私有方法吗?私有变量呢?多重继承?
- 【Leetcode】之ZigZag Conversion
- cnetos 6----install ---- rpmfusion
- Han gm an Judge 模拟