[Codeforces] Round #353 (Div. 2)

A题题意:给出一个等差数列的首项和公差,求x是否是该数列中的项

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main(){
 4     int a,b,c;
 5     scanf("%d%d%d",&a,&b,&c);
 6     if(c>0&&b-a>=0&&(b-a)%c==0)printf("YES\n");
 7     else if(c<0&&a-b>=0&&(a-b)%(-c)==0)printf("YES\n");
 8     else if(c==0&&a==b)printf("YES\n");
 9     else printf("NO\n");
10     return 0;
11 }

B题题意:九宫格中可以填入[1,n]的数字,固定上中,中左,中右,下中,求方案数

 1 //long long
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 int main(){
 5     int n,a,b,c,d;
 6     scanf("%d%d%d%d%d",&n,&a,&b,&c,&d);
 7     long long ans=0;
 8     for(int i=1;i<=n;i++){
 9         int x=b+i-c;
10         if(x<1||x>n)continue;
11         x=a+i-d;
12         if(x<1||x>n)continue;
13         x=a+b+i-c-d;
14         if(x<1||x>n)continue;
15         ans++;
16     }
17     printf("%I64d\n",ans*n);
18     return 0;
19 }

C题题意:给出n个点,每个点有一个权值(保证权值和为0),围成一个环,每次可以把一个点的任意多权值移向相邻的

     求把所有点权值均变成0的最小步数

题解:把一段长度为n,和为0的序列都变成0需要n-1步

   所以求ans的最小值即求把序列划分为尽量多的和为0的序列

   我们对整个序列求前缀和,若某一段和0,则这一段之前的前缀和与加上这一段的前缀和相同(与hnoi2016day2T3思想相似)

   所以我们可以通过求前缀和中出现最多的数来求

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define maxn 100005
 4 map<long long,int>tong;
 5 int n;
 6 long long A[maxn];
 7 int main(){
 8     scanf("%d",&n);
 9     int Max=0;
10     for(int i=1;i<=n;i++){
11         scanf("%I64d",&A[i]);
12         A[i]+=A[i-1];
13         Max=max(Max,++tong[A[i]]);
14     }
15     printf("%d\n",n-Max);
16     return 0;
17 }

刀题比C题好做QAQ

刀题题意:求给定序列中每个点在二叉搜索树中的父亲节点的权值

题解:某点在二叉搜索树中的父亲一定是它之前比它小的最大的数或它只前比它大的最小的数中没有对应儿子的内个,

   因为他俩之间没有其他的点,所以其中一个一定是另一个的儿砸www

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define maxn 100005
 4 #define mp make_pair
 5 #define fir first
 6 #define sec second
 7 set<pair<int,int> >seq;
 8 set<pair<int,int> >::iterator it;
 9 int n,A[maxn],l[maxn],r[maxn],fa[maxn];
10 int main(){
11     scanf("%d%d",&n,&A[1]);
12     seq.insert(mp(A[1],1));
13     for(int i=2;i<=n;i++){
14         scanf("%d",&A[i]);
15         it=seq.upper_bound(mp(A[i],i));
16         if(it!=seq.end()&&!l[(*it).sec])
17                 l[(*it).sec]=i,fa[i]=(*it).sec;
18         else if(!r[(*--it).sec])
19                 r[(*it).sec]=i,fa[i]=(*it).sec;
20         seq.insert(mp(A[i],i));
21     }
22     for(int i=2;i<=n;i++)
23         printf("%d ",A[fa[i]]);
24     printf("\n");
25     return 0;
26 }

E题题意:给定一个1到n的序列和一个数组A[i],每个点i可以到达i+1,i+2...A[i](1<=A[i]<=n)

     dist[i][j]表示i到j经过的线段数的最小值

     求sigma(dist[i][j])

题解:设dp[i]表示sigma(dist[i][j])

   dp[i]=min(dp[j]+(n-i)-(A[i]-j))(i<j<=A[i])

   |--------------|                                                                                                                                                                                                                                              i                 A[i]                                                                                                                                                                                                                                                    |---------------------------------|                                                                                                                                                                                                                        j                                         n

dp[i]到dp[j]的转移,先把所有点经过的线段数都加1,即总共加n-i,然而j到A[i]可以直接到达,所以减去A[i]-j,用线段树维护

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 #define lson rt<<1,l,mid
 5 #define rson rt<<1|1,mid+1,r
 6 #define inf 0x7f7f7f7f7f7f7f7f
 7 #define maxn 100005
 8 ll tree[maxn<<2];
 9 int n,a[maxn];
10 void update(int rt,int l,int r,int pos,ll val){
11     if(l==r){ tree[rt]=val; return; }
12     int mid=(l+r)>>1;
13     if(pos<=mid)update(lson,pos,val);
14     else update(rson,pos,val);
15     tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
16 }
17 ll query(int rt,int l,int r,int ql,int qr){
18     if(ql<=l&&qr>=r)return tree[rt];
19     int mid=(l+r)>>1;
20     ll ans=inf;
21     if(ql<=mid)ans=min(ans,query(lson,ql,qr));
22     if(qr>mid)ans=min(ans,query(rson,ql,qr));
23     return ans;
24 }
25 int main(){
26     scanf("%d",&n);
27     for(int i=1;i<n;i++)
28         scanf("%d",&a[i]);
29     memset(tree,0x7f,sizeof(tree));//维护dp[i]+i的最小值
30     update(1,1,n,n,n);//dp[n]=0
31     ll ans=0;
32     for(int i=n-1;i;i--){
33         ll val=query(1,1,n,i+1,a[i])+n-a[i]-i;
34         ans+=val,update(1,1,n,i,val+i);
35     }
36     printf("%I64d\n",ans);
37     return 0;
38 }

时间: 2024-08-26 15:00:16

[Codeforces] Round #353 (Div. 2)的相关文章

Codeforces Round #353 (Div. 2) D. Tree Construction (二分,stl_set)

题目链接:http://codeforces.com/problemset/problem/675/D 给你一个如题的二叉树,让你求出每个节点的父节点是多少. 用set来存储每个数,遍历到a[i]的时候查找比a[i]大的数的位置,然后插入,而父亲就是刚好比a[i]小的数或刚好大的数. 然后讨论是哪一个数. 比如给你3 1 2 ,如图 1的父亲是3 ,2的父亲是1. 那我其实只要找左边或右边出现最晚的数就行了,用pair的first表示a[i],second表示出现的顺序i. 1 #include

Codeforces Round #353 (Div. 2) C. Money Transfers

题目大意:某个人在N个银行的存款和借款总和为0,这N个银行排成一个圆环,每次转账只能在相邻的两个银行之间进行.问进行多少次转账能使每个银行的存款为0. 题目保证总和一定是0. 有两个理论基础需要先说明. 一个总和为0的长度为N的区间内至多转账N-1次就可以使每个账户存款为0.因此只要找出总和为0的区间个个数最多设为W,那么答案就是N-W 一个区间总和为零的充要条件是,第一个元素之前的前缀和等于最后一个元素截止的前缀和. #include <iostream> #include <map&

Codeforces Round #353 (Div. 2) D. Tree Construction (BST询问父亲节点)

原题请戳这里 题意: 给出n个不同的数,按照给出的顺序构造二叉排序树BST,第1个数为根节点.输出2-n个 节点的父亲节点. 分析: 二叉排序树的平均复杂度是log2n,最坏情况下变成线性的,复杂度为n. 对n个节点的插入操作如果用结构体指针的写法最坏情况下为n2=1010,这样会超时. 开始没有注意这点,TLE.但是正好复习了BST的插入操作递归和非递归的写法. 易知,插入的数的父亲节点是已插入的比它大或者比它小的与其最接近的数之一. 这个题利用set保存输入的数,用两个map分别记录左右孩子

Codeforces Round #353 (Div. 2) ABCDE 题解 python

Problems # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring Painting standard input/output 1 s, 256 MB    x2519 C Money Transfers standard input/output 1 s, 256 MB    x724 D Tree Construction standard input/output 2

Codeforces Round #353 (Div. 2)Restoring Painting

Vasya works as a watchman in the gallery. Unfortunately, one of the most expensive paintings was stolen while he was on duty. He doesn't want to be fired, so he has to quickly restore the painting. He remembers some facts about it. The painting is a

Codeforces Round #353 (Div. 2) C. Money Transfers (思维)

原题请戳这里 题意: n个银行成环形排列.每个银行有一定的余额ai,每次可以在任意相邻的银行间转账.问 最少需要经过多少次转账使得所有银行的余额都为0. 分析: 由于所有银行的余额总数为0,则若把整个环看成一段,需要n-1次使所有余额为0. 把ai分为k个sum=0的部分,每部分的长度为li,使每个部分所有银行清零需要li-1步.n个 银行清零总共需要n-k步. 因此即是求(n-k)min,那么k值越大越好. 考虑前缀和,若sum[i]==sum[j],则区间[i+1,j]必定和为0,且[j+1

数据结构 - Codeforces Round #353 (Div. 2) D. Tree Construction

Tree Construction Problem's Link ---------------------------------------------------------------------------- Mean: 给定n个数,按照构造Binary Search Tree的方式来构造BST树,按顺序输出每一个非root结点的父节点的值. analyse: 构造BST树最坏情况下时间复杂度为O(n),肯定会超时. 注意到只需要输出结点的父节点的值,不需要真的构造BST树. 插到第i

Codeforces Round #353 (Div. 2) A. Infinite Sequence

Vasya likes everything infinite. Now he is studying the properties of a sequence s, such that its first element is equal to a (s1 = a), and the difference between any two neighbouring elements is equal to c (si - si - 1 = c). In particular, Vasya won

Codeforces Round #353 (Div. 2) A. Infinite Sequence 思维题

A. Infinite Sequence time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Vasya likes everything infinite. Now he is studying the properties of a sequence s, such that its first element is equal