[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 }