T1:CCT
题解:对于一个特征a1a2a3…am,我们可以用(a1-a1)(a2-a1)…(am-a1)来表示它。然后再做对每一位前缀和(s1-s1)(s2-s1)(s3-s1)…(sm-s1)。易发现:当两个位置i,j前缀和相同时,i+1到j或i到j-1即是一种可行的选法。用set记住每个前缀和最早出现的位置,对每个位置在set中查询并更新答案即可。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 #include<set> 7 using namespace std; 8 int n,x,ans=0,k; 9 struct node{ 10 int num; 11 int dif[31]; 12 bool operator <(const node &b)const{ 13 int i; 14 for(i=1;i<k;++i){ 15 if(dif[i]!=b.dif[i]) return dif[i]<b.dif[i]; 16 } 17 return false; 18 } 19 }t; 20 std::set<node> s; 21 std::set<node>::iterator it; 22 int sum[100001][31]; 23 int max(int a,int b){ 24 return a>b?a:b; 25 } 26 int main(){ 27 freopen("cct.in","r",stdin); 28 freopen("cct.out","w",stdout); 29 scanf("%d%d",&n,&k); 30 int i,j; 31 for(i=1;i<=n;++i){ 32 scanf("%d",&x); 33 for(j=1;j<=k;++j){ 34 sum[i][j]=sum[i-1][j]; 35 if(x&(1<<(j-1))) sum[i][j]++; 36 } 37 } 38 ans=0;t.num=0; 39 for(i=1;i<k;++i){ 40 t.dif[i]=0; 41 } 42 s.insert(t); 43 for(i=1;i<=n;++i){ 44 t.num=i; 45 for(j=1;j<k;++j){ 46 t.dif[j]=sum[i][j]-sum[i][j+1]; 47 } 48 it=s.find(t); 49 if(it==s.end()) s.insert(t); 50 else ans=max(ans,i-(*it).num); 51 } 52 printf("%d\n",ans); 53 return 0; 54 }
- - - - - - - - - - - - - - - - -
T2:MHM
题解:二分上课的节数并check。类似题目请参考NOIP2015跳石头。注意在输入完要先排序。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 using namespace std; 8 int n,m,k,l,r,mid,ans; 9 int a[50010],wake[50010]; 10 bool check(int x){ 11 int cnt=0,now=0; 12 for(int i=1;i<=m;++i){ 13 if(wake[i]+now<x){ 14 now+=wake[i]+1; 15 cnt++; 16 } 17 else now=0; 18 } 19 if(cnt>k) return false; 20 else return true; 21 } 22 int main(){ 23 freopen("mhm.in","r",stdin); 24 freopen("mhm.out","w",stdout); 25 scanf("%d%d%d",&n,&m,&k); 26 int i,j; 27 for(i=1;i<=m;++i){ 28 scanf("%d",a+i); 29 } 30 a[0]=0;a[++m]=n; 31 sort(a,a+m+1); 32 for(i=1;i<=m;++i){ 33 wake[i]=a[i]-a[i-1]-1; 34 } 35 l=0;r=n; 36 while(l+1<r){ 37 int mid=(l+r)>>1; 38 if(check(mid)) l=mid; 39 else r=mid-1; 40 } 41 if(check(r)) ans=r; 42 else ans=l; 43 printf("%d\n",ans); 44 return 0; 45 }
- - - - - - - - - - - - - - - -
T3:AAFA
题解:按照截至时间排序从前往后选。当选到第i个时,若已经选择的题目数量小于ti,则该时间选择它必定比不选更优。若已经选择的题目数量等于ti,则比较第i题的收益和已选择题目的最小收益,取更优者。已选择的题目用优先队列维护。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<vector> 9 #define ll long long 10 using namespace std; 11 struct node{ 12 ll t,w; 13 }te[100010]; 14 int n,ti=0; 15 ll ans=0,s; 16 bool cmp(node a,node b){ 17 if(a.t==b.t) return a.w>b.w; 18 return a.t<b.t; 19 } 20 priority_queue<int,vector<int>,greater<int> > pq; 21 int main(){ 22 freopen("aafa.in","r",stdin); 23 freopen("aafa.out","w",stdout); 24 scanf("%d",&n); 25 int i,j; 26 for(i=1;i<=n;++i){ 27 scanf("%lld%lld",&te[i].t,&te[i].w); 28 //ti=max(ti,te[i].t); 29 } 30 sort(te+1,te+n+1,cmp); 31 int cnt=1; 32 ans=0; 33 for(i=1;i<=n;++i){ 34 s=pq.size(); 35 if(s<te[i].t) pq.push(te[i].w); 36 else{ 37 if(s==te[i].t){ 38 if(pq.top()<te[i].w){ 39 pq.pop(); 40 pq.push(te[i].w); 41 } 42 } 43 } 44 } 45 ans=0; 46 while(!pq.empty()){ 47 ans+=pq.top();pq.pop(); 48 } 49 printf("%lld\n",ans); 50 return 0; 51 }
- - - - - - - - - - - - -
T4:ZZI
题解:在一个房子造发电机可以看作把它和已经通电的房子连边,权值为0,因此改变边权直接跑最小生成树即可。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 #define inf 0x7f7f7f7f 7 using namespace std; 8 int n,ans,minn=inf; 9 int v[310],dist[310]; 10 int a[310][310]; 11 bool used[310]; 12 int min(int a,int b){ 13 return a<b?a:b; 14 } 15 int prim(){ 16 int next,maxn,res=0; 17 int i,j; 18 for(;;){ 19 next=-1;maxn=inf; 20 for(i=1;i<=n;++i){ 21 if(!used[i] &&dist[i]<maxn){ 22 maxn=dist[i];next=i; 23 } 24 } 25 if(next==-1) break ; 26 used[next]=true; 27 res+=dist[next];//dist[next]=0; 28 for(i=1;i<=n;++i){ 29 if(!used[i]) dist[i]=min(dist[i],a[next][i]); 30 } 31 } 32 return res; 33 } 34 int main(){ 35 freopen("zzi.in","r",stdin); 36 freopen("zzi.out","w",stdout); 37 scanf("%d",&n); 38 int i,j; 39 minn=inf; 40 for(i=1;i<=n;++i){ 41 scanf("%d",dist+i); 42 } 43 for(i=1;i<=n;++i){ 44 for(j=1;j<=n;++j){ 45 scanf("%d",&a[i][j]); 46 } 47 } 48 printf("%d\n",prim()); 49 return 0; 50 }