题目见LOJ
T1 决斗
40pts直接贪心
考虑我们主要的问题是多人经过一个点,我们找出没有人继续向前走的那个点(容易想到至少存在一个这样的点),然后从那个点下一个点开始贪心就行了
具体怎么找?对每个点的人数(减一)做前缀和,前缀和最小的地方就是那个点、
(因打字带空格,printf("%d",ans);变成printf("%d ",ans);,导致不忽略行末空格的情况下成功gg
1 #include<set> 2 #include<cstdio> 3 #include<vector> 4 #include<cstring> 5 #include<algorithm> 6 #define sint set<int> 7 #define sit set<int>::iterator 8 #define vint vector<int> 9 #define vit vector<int>::iterator 10 using namespace std; 11 const int N=500005; 12 int n,sum,ans,minn,noww; 13 int a[N],dwf[N],elf[N]; 14 vint ve[N]; sint st; 15 int main() 16 { 17 scanf("%d",&n),noww=1,minn=n+1; 18 for(int i=1;i<=n;i++) 19 { 20 scanf("%d",&a[i]); 21 ve[a[i]].push_back(i); 22 } 23 for(int i=1;i<=n;i++) scanf("%d",&dwf[i]); 24 for(int i=1;i<=n;i++) scanf("%d",&elf[i]); 25 for(int i=1;i<=n;i++) 26 { 27 sum+=ve[i].size()-1; 28 if(sum<minn) minn=sum,noww=i; 29 } 30 if(++noww>n) noww=1; 31 for(int i=1;i<=n;i++) 32 { 33 vint v=ve[noww]; 34 for(vit it=v.begin();it!=v.end();it++) 35 st.insert(elf[*it]); 36 sit ir=st.lower_bound(dwf[noww]); 37 if(ir==st.end()) st.erase(st.begin()); 38 else ans++,st.erase(ir); 39 if(++noww>n) noww=1; 40 } 41 printf("%d",ans); 42 return 0; 43 }
T2 数列
把序列反过来接在前面,这样在左边写数相当于在前半部分选,再右边写数相当于在后半部分选
(然后考试的时候就在第二问上墨迹了半天
维护一个权值树状数组,记录以每个数结尾的长度和出现在不同写法序列中的总方案,然后长度相同时合并答案。最终答案即 方案数* 2^(总长度-LIS长度-1)(除了LIS以外的都可以在两边随便填,还要刨掉第一个填上去的)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=400005,mod=1e9+7; 6 struct a{int len,cnt;}bit[N]; 7 void Add(int &x,int y) 8 { 9 x+=y; 10 if(x>=mod) x-=mod; 11 } 12 a operator + (a x,a y) 13 { 14 int l1=x.len,l2=y.len; 15 if(l1^l2) return l1>l2?x:y; 16 else return (a){l1,(x.cnt+y.cnt)%mod}; 17 } 18 int uni[N],b[N],n,rd,lth; 19 a Query(int pos) 20 { 21 a ret=(a){0,0}; 22 while(pos) 23 { 24 ret=ret+bit[pos]; 25 pos-=pos&-pos; 26 } 27 return ret; 28 } 29 void Change(int pos,a tsk) 30 { 31 while(pos<=lth) 32 { 33 bit[pos]=bit[pos]+tsk; 34 pos+=pos&-pos; 35 } 36 } 37 int Qpow(int x,int k) 38 { 39 if(k==1) return x; 40 int tmp=Qpow(x,k/2); 41 return k%2?1ll*tmp*tmp%mod*x%mod:1ll*tmp*tmp%mod; 42 } 43 int main() 44 { 45 scanf("%d",&n); 46 for(int i=1;i<=n;i++) 47 { 48 scanf("%d",&rd); 49 uni[i]=b[i+n]=b[n-i+1]=rd; 50 } 51 sort(uni+1,uni+1+n); 52 lth=unique(uni+1,uni+1+n)-1-uni,n*=2; 53 for(int i=1;i<=n;i++) 54 b[i]=lower_bound(uni+1,uni+1+lth,b[i])-uni; 55 for(int i=1;i<=n;i++) 56 { 57 a qry=Query(b[i]-1); 58 if(++qry.len==1) qry.cnt=1; 59 Change(b[i],qry); 60 } 61 a ans=Query(lth); n>>=1; 62 if(ans.len==n) printf("%d 1",n); 63 else printf("%d %lld",ans.len,1ll*ans.cnt*Qpow(2,n-ans.len-1)%mod); 64 return 0; 65 }
T3 打苍蝇
判断点是否在多边形内->THUPC2018 赛艇,告辞