2018 Multi-University Training Contest 2
Posted changer-qyz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018 Multi-University Training Contest 2相关的知识,希望对你有一定的参考价值。
比个辣鸡.jpg
D.Game
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6312
题意:给一个数字n,就代表有一个1~n的序列,A和B两个人分别可以对这个序列进行操作,每次操作可以删去一个数及这个数所有的因子,轮到谁时谁无法再进行操作谁就输了,也就是刚好删除最后一个数的人赢。A先走,问A能不能赢。
分析:从1-n,我们可以先不看1,因为删除任何一个数都可以顺便把1删除了,那么只从2~n中选择就一定有一个胜者,如果这个状态A胜的话,我们就可以选择那个让我们胜的数,如果A输,我们可以先去掉1来转变状态,这样A还是会胜。所以A是必胜的,只用输出YES就行了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main(){ 4 int n; 5 while(~scanf("%d",&n)){ 6 printf("Yes "); 7 } 8 return 0; 9 }
G.Naive Operations
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6315
题意:有两个数字序列An和Bn,An里的元素一开始全为0,Bn数组由题目给出。现在有两种操作:
add l r 表示在An数组区间( l , r )中的每一个数都加1;query l r 表示查询区间( l , r )的ai/bi的和。
分析:涉及到区间更新区间和区间求和,所以考虑线段树。
当然如果单纯的用线段树一点一点更新肯定复杂度太高,只有当 ai 加1的次数能够整除 bi 时才会对区间答案有贡献,这样用线段树记录一开始每个点初始化为bi,每次访问的区间有这个点就减1,当为0时表示可以整除bi此位置的贡献加1,然后向下查找初始的bi的值重新赋值,而当查询区间的和时,加上每个点的贡献就行了。
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #define maxn 100005 5 using namespace std; 6 struct point{ 7 int l,r; 8 int num,sum,b; 9 int lazy; 10 }tree[maxn<<2]; 11 int n,m; 12 void build(int root,int l,int r){ 13 tree[root].l=l;tree[root].r=r; 14 tree[root].sum=0;tree[root].lazy=0; 15 if (l==r){ 16 cin >> tree[root].b; 17 tree[root].num=tree[root].b; 18 tree[root].sum=0; 19 return ; 20 } 21 int mid=(l+r)/2; 22 build(root<<1,l,mid); 23 build(root<<1|1,mid+1,r); 24 tree[root].num=min(tree[root<<1].num,tree[root<<1|1].num); 25 } 26 void pushdown(int root){ 27 if (tree[root].lazy){ 28 tree[root<<1].lazy+=tree[root].lazy; 29 tree[root<<1|1].lazy+=tree[root].lazy; 30 tree[root<<1].num+=tree[root].lazy; 31 tree[root<<1|1].num+=tree[root].lazy; 32 tree[root].lazy=0; 33 } 34 } 35 void update(int root,int l,int r){ 36 if (tree[root].l==l && tree[root].r==r){ 37 tree[root].num--; 38 if (tree[root].num){ 39 tree[root].lazy--; 40 return ; 41 } 42 else{ 43 if (tree[root].l==tree[root].r){ 44 tree[root].sum++; 45 tree[root].num=tree[root].b; 46 return ; 47 } 48 } 49 } 50 pushdown(root); 51 int mid=(tree[root].l+tree[root].r)/2; 52 if (r<=mid) update(root<<1,l,r); 53 else if (l>mid) update(root<<1|1,l,r); 54 else{ 55 update(root<<1,l,mid); 56 update(root<<1|1,mid+1,r); 57 } 58 tree[root].num=min(tree[root<<1].num,tree[root<<1|1].num); 59 tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum; 60 } 61 int query(int root,int l,int r){ 62 if (tree[root].l==l && tree[root].r==r){ 63 return tree[root].sum; 64 } 65 int mid=(tree[root].l+tree[root].r)/2; 66 if (r<=mid) return query(root<<1,l,r); 67 else if (l>mid) return query(root<<1|1,l,r); 68 else{ 69 return query(root<<1,l,mid)+query(root<<1|1,mid+1,r); 70 } 71 } 72 int main(){ 73 string ss; 74 int x,y; 75 ios::sync_with_stdio(false); 76 cin.tie(0);cout.tie(0); 77 while (cin >> n >> m){ 78 build(1,1,n); 79 for (int i=0;i<m;i++){ 80 cin >> ss >> x >> y; 81 if (ss[0]==‘a‘){ 82 update(1,x,y); 83 } 84 else{ 85 int ans=query(1,x,y); 86 cout << ans << endl; 87 } 88 } 89 } 90 return 0; 91 }
J.Swaps and Inversions
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6318
题意:给一串数字序列,每一对逆序对需要耗费x。也可以任意相邻位置交换来减少逆序对数,交换一次的代价是y。问至少要付出的代价是多少。
分析:逆序对数==最少交换相邻位置次数,只需要求出逆序对数*min(x,y)。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #define maxn 100005 6 using namespace std; 7 typedef long long ll; 8 struct point{ 9 ll num; 10 int id; 11 }a[maxn]; 12 ll tree[maxn]; 13 int b[maxn]; 14 int n,x,y; 15 ll ans; 16 int comp(point p,point q){ 17 return p.num<q.num || p.num==q.num && p.id<q.id; //数字相同是,注意离散化时的重复 18 } 19 int lowbit(int x){ 20 return x & (-x); 21 } 22 void add(int x,int num){ 23 while (x<=n){ 24 tree[x]+=num; 25 x+=lowbit(x); 26 } 27 } 28 ll query(int x){ 29 ll sum=0; 30 while (x>0){ 31 sum+=tree[x]; 32 x-=lowbit(x); 33 } 34 return sum; 35 } 36 int main(){ 37 ios::sync_with_stdio(false); 38 cin.tie(0);cout.tie(0); 39 while (cin >> n >> x >> y){ 40 memset(tree,0,sizeof(tree)); 41 for (int i=1;i<=n;i++){ 42 cin >> a[i].num; 43 a[i].id=i; 44 } 45 sort(a+1,a+1+n,comp); 46 for (int i=1;i<=n;i++){ 47 b[a[i].id]=i; 48 } 49 ans=0; 50 for (int i=1;i<=n;i++){ 51 ans+=i-1-query(b[i]); 52 add(b[i],1); 53 } 54 if (x<=y) cout << x*ans << endl; 55 else cout << y*ans << endl; 56 } 57 return 0; 58 }
1 #include<iostream> 2 #include<cstring> 3 #define maxn 100005 4 using namespace std; 5 typedef long long ll; 6 ll ans; 7 ll a[maxn],t[maxn]; 8 int n,x,y; 9 void merge_sort(int l,int r){ 10 if (r-l>=1){ 11 int mid=(r-l)/2+l; 12 int p=l,q=mid+1,i=l; 13 merge_sort(l,mid); 14 merge_sort(mid+1,r); 15 while (p<=mid || q<=r){ 16 if (q>r || p<=mid && a[p]<=a[q]) t[i++]=a[p++]; 17 else { 18 t[i++]=a[q++]; 19 ans+=mid+1-p; 20 } 21 } 22 for (i=l;i<=r;i++) a[i]=t[i]; 23 } 24 } 25 int main(){ 26 ios::sync_with_stdio(false); 27 cin.tie(0);cout.tie(0); 28 while (cin >> n >> x >> y){ 29 for (int i=1;i<=n;i++){ 30 cin >> a[i]; 31 } 32 ans=0; 33 merge_sort(1,n); 34 if (x<=y) cout << x*ans << endl; 35 else cout << y*ans << endl; 36 } 37 return 0; 38 }
以上是关于2018 Multi-University Training Contest 2的主要内容,如果未能解决你的问题,请参考以下文章
2018 Multi-University Training Contest 2
2018 Multi-University Training Contest 9
2018 Multi-University Training Contest 4
2018 Multi-University Training Contest 4