比赛传送门:http://codeforces.com/contest/675
A:水题
判断是否在等差数列里,一定要分类讨论公差正负,b和a的大小,不能直接模
B:水题
5个位置变量设为x1到x5,发现4个正方形里都有x3,所以x3是有n种取法,接下来就是x1取定,另外3个都取定了,算出另外3个由x1表达的式子,判断是否在范围里即可
C:前缀和
给你n个数字,围成一个圈,然后总和为0,有一种操作是可以把一个数字,给周围两个数字中的一个一些值,就比如有-3 和3,3能给-3 3这么多值,然后他们就变成了0 0,这是一次操作,然后问你最少多少次操作,能变成全0
考虑一段值,和为0,他们变成全0,只需要长度-1次操作,这是肯定的,所以就是找出那些和为0的段
这个该怎么找呢,可以把前缀和都求出来,这样一段长度为n的前缀和数组,里面有些是0有些不是0,不是0都是成段出现,这连续的段的长度就是这一段需要移动的次数,所以只需要考虑长度n的前缀和数组里面不是0的个数
但是这n个数字是一个圈,所以不一定是从1开始到n,可能2到n+1之类的,所以需要把长度n补为2n,然后在里面考虑长度n的前缀和,当你考虑2到n+1的时候,应该找里面不为sum[1]的个数,因为这个前缀和是要减去sum[1]的
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; #define MAX 200005 #define MAXN 1000005 #define maxnode 15 #define sigma_size 30 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define middle int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem(x,v) memset(x,v,sizeof(x)) #define lowbit(x) (x&-x) #define pii pair<int,int> #define bits(a) __builtin_popcount(a) #define mk make_pair #define limit 10000 //const int prime = 999983; const int INF = 0x3f3f3f3f; const LL INFF = 0x3f3f; const double pi = acos(-1.0); const double inf = 1e18; const double eps = 1e-8; const LL mod = 1e9+7; const ull mx = 133333331; /*****************************************************/ inline void RI(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; } /*****************************************************/ map<LL,int> ma; int a[MAX]; LL sum[MAX]; int main(){ //freopen("in.txt","r",stdin); int n; while(cin>>n){ ma.clear(); sum[0]=0; for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i]; for(int i=n+1;i<=2*n;i++) sum[i]=sum[i-1]+a[i-n]; for(int i=1;i<=n;i++){ if(!ma.count(sum[i])) ma[sum[i]]=0; ma[sum[i]]++; } int maxn=ma[0]; for(int i=n+1;i<=2*n;i++){ ma[sum[i-n]]--; ma[sum[i]]++; maxn=max(maxn,ma[sum[i-n]]); } cout<<n-maxn<<endl; } return 0; }
D:排序+set
构造二叉搜索树,问你按照顺序放进去每个节点,它的父节点是什么
暴力肯定会TLE辣,如果是一条链,就退化到O(n^2)了
要考虑二叉搜索树的性质,把一棵二叉搜索树投影到横轴上,数列是有序的,所以可以先排序,然后按照顺序往里面放,记录每个点的左右儿子是否都已经被占领即可,每次放进去的时候找比它小的第一个和比它大的第一个就行,然后考虑比它小的的右儿子,比它大的的左儿子,必定只有一个满足(因为小的放进去,已经占领了大的左儿子,或者大的放进去占领了小的右儿子,所以必定只有一个解)
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; #define MAX 100005 #define MAXN 1000005 #define maxnode 15 #define sigma_size 30 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define middle int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem(x,v) memset(x,v,sizeof(x)) #define lowbit(x) (x&-x) #define pii pair<int,int> #define bits(a) __builtin_popcount(a) #define mk make_pair #define limit 10000 //const int prime = 999983; const int INF = 0x3f3f3f3f; const LL INFF = 0x3f3f; const double pi = acos(-1.0); const double inf = 1e18; const double eps = 1e-8; const LL mod = 1e9+7; const ull mx = 133333331; /*****************************************************/ inline void RI(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; } /*****************************************************/ set<int> s; map<int,int> l,r; int main(){ //freopen("in.txt","r",stdin); int n; while(cin>>n){ l.clear(),r.clear();s.clear(); for(int i=0;i<n;i++){ int a; scanf("%d",&a); if(i){ set<int>::iterator L=s.lower_bound(a); set<int>::iterator R=s.lower_bound(a); if(L==s.begin()){ printf("%d",*R); l[*R]=a; } else if(R==s.end()){ L--; printf("%d",*L); r[*L]=a; } else{ L--; if(r[*L]){ printf("%d",*R); l[*R]=a; } else{ printf("%d",*L); r[*L]=a; } } } s.insert(a); if(i){ if(i==n-1) printf("\n"); else printf(" "); } } } return 0; }
给你第i个车站,可以买到i+1到ai的车站的票,p[i,j]为从i到j的用的最少的车票,问你sigma(p[i,j])
考虑p[i]为第i个车站往后面的所有车站走的最小值,能直接到i+1到ai,所以i+1 - ai之间的车站肯定是1次就能到达,后面的那些车站如何最小化呢,应该要在i+1 - ai之间找一个过渡点,哪个最优呢,我原本考虑是p[i]最小的,但是发现并不行,因为p[i]最小,不代表去掉i能1次到达的那些站之后还是最小,所以应该考虑区间里面能到达最远地方的那个车站,因为它能走的最远,它用一次票走到的地方更多,所以它最优,线段树维护下即可
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; #define MAX 100005 #define MAXN 1000005 #define maxnode 15 #define sigma_size 30 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define middle int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem(x,v) memset(x,v,sizeof(x)) #define lowbit(x) (x&-x) #define pii pair<int,int> #define bits(a) __builtin_popcount(a) #define mk make_pair #define limit 10000 //const int prime = 999983; const int INF = 0x3f3f3f3f; const LL INFF = 0x3f3f; const double pi = acos(-1.0); const double inf = 1e18; const double eps = 1e-8; const LL mod = 1e9+7; const ull mx = 133333331; /*****************************************************/ inline void RI(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; } /*****************************************************/ LL p[MAX]; pii maxv[MAX<<2]; int a[MAX]; void pushup(int rt){ maxv[rt]=max(maxv[rrt],maxv[lrt]); } void build(int l,int r,int rt){ if(l==r){ maxv[rt]=mk(0,l); return; } middle; build(lson); build(rson); } void update(int l,int r,int rt,int pos,int d){ if(l==r){ maxv[rt]=mk(d,pos); return ; } middle; if(pos<=m) update(lson,pos,d); else update(rson,pos,d); pushup(rt); } pii query(int l,int r,int rt,int L,int R){ if(L<=l&&r<=R) return maxv[rt]; middle; pii u=mk(0,0); if(L<=m) u=max(u,query(lson,L,R)); if(R>m) u=max(u,query(rson,L,R)); return u; } int main(){ //freopen("in.txt","r",stdin); int n; while(cin>>n){ for(int i=1;i<n;i++) scanf("%d",&a[i]); p[n-1]=1; build(1,n,1); update(1,n,1,n-1,a[n-1]); LL ans=p[n-1]; for(int i=n-2;i>0;i--){ pii u=query(1,n,1,i+1,a[i]); p[i]=a[i]-i+(p[u.second]-(a[i]-u.second))+(n-a[i]); update(1,n,1,i,a[i]); ans+=(LL)p[i]; } cout<<ans<<endl; } return 0; }