剧毒比赛,至少涨了分对吧。: (
【A】Left-handers, Right-handers and Ambidexters
题意:
有\(l\)个右撇子,\(r\)个左撇子,\(a\)个双手都惯用的人。
要让他们组成两个队伍,一边用左手,一边用右手,这两个队伍人数要相同。
问最大人数。
题解:
随便搞……
#includeusing namespace std;int l,r,a;int main(){ scanf("%d%d%d",&l,&r,&a); if(l>r) swap(l,r); if(l+a<=r) {printf("%d",(l+a)*2); return 0;} printf("%d",(l+a+r)/2*2); return 0;}
【B】Intercepted Message
题意:
有两个数组\(x_1,x_2,\cdots,x_n\),\(y_1,x_2,\cdots,y_m\)。
要把这两个数组分成若干个子串(个数相等,从左到右一一对应)。
并且每个对应子串的和相等,问最多子串个数。
题解:
贪心,双指针扫过去。
#include#define F(i,a,b) for(int i=(a);i<=(b);++i)int n,m,ans;int a[100001],b[100001];int main(){ scanf("%d%d",&n,&m); F(i,1,n) scanf("%d",a+i); F(i,1,m) scanf("%d",b+i); int l=1,sum1=0,sum2=0; F(i,1,n){ sum1+=a[i]; while(sum2+b[l]<=sum1) sum2+=b[l] ,++l; if(sum2==sum1) ++ans, sum1=sum2=0; } printf("%d",ans); return 0;}
【C】Zebras
题意:
给定一个01串,把它分成若干个子序列的并,不重复不遗漏。
并且要满足每个子序列都是斑马序列。
斑马序列的定义是,以0开始,01交替出现,并且以0结尾的字符串。
如果可行,输出任意方案,不可行输出-1。
题解:
set暴力上贪一波心。01分开set,能选就选。
#include#define F(i,a,b) for(int i=(a);i<=(b);++i)#define F2(i,a,b) for(int i=(a);i<(b);++i)using namespace std;int n;int arr[200007],tot,cnt;char str[200007];vector ans[200007];set st1,st2;set ::iterator iter;int main(){ scanf("%s",str+1); n=strlen(str+1); F(i,1,n) if(str[i]=='0') st1.insert(i); else st2.insert(i); while(!st1.empty()){ ++tot; int lst=*st1.lower_bound(0); st1.erase(lst); ans[tot].push_back(lst); while(1){ int tmp1,tmp2; iter=st2.lower_bound(lst); if(iter==st2.end()) break; tmp1=*iter; iter=st1.lower_bound(tmp1); if(iter==st1.end()) break; tmp2=*iter; st2.erase(tmp1), st1.erase(tmp2); ans[tot].push_back(tmp1); ans[tot].push_back(tmp2); lst=tmp2; } } if(!st2.empty()){puts("-1"); return 0;} printf("%d\n",tot); F(i,1,tot){ printf("%d ",ans[i].size()); F2(j,0,ans[i].size()) printf("%d ",ans[i][j]); puts(""); } return 0;}
【D】A Leapfrog in the Array
题意:略复杂,看。
题解:
瞎找规律。
当前的len一开始为n,如果位置pos在这一串的"固定点"(一开始为奇数位)上,直接输出。
否则进行一波跳,len大致减半,pos大致减半,固定点的奇偶性随着len的奇偶性改变,答案加上跳过的数。
这么一波分类讨论一下就OK。
#include#define F(i,a,b) for(int i=(a);i<=(b);++i)typedef long long ll;ll n; int q;int main(){ scanf("%lld%d",&n,&q); F(i,1,q){ ll x, ans=0, len=n; int k=0; scanf("%lld",&x); while(x%2==k){ ans+=k==0?(len+1)/2:len/2; x=(x+k)/2; int len2=len; len=k==0?len/2:(len+1)/2; k^=(len2&1); } printf("%lld\n",ans+(x+(k^1))/2); } return 0;}
【E】Data Center Maintenance
题意:略复杂,看。
题解:
对于两个数据中心,如果有一个数据保存在这两个数据中心中,并且这两个数据中心的维护时间差1小时,那么如果其中一个时间小的移动了维护时间,另一个必然也要移动。
这是一个连锁反应,我们先把这种关系连成有向图。
那么对于一个圈,要不然全部取要不然全部不取。所以先强连通分量缩一波点。
然后得到一个DAG,那么如果取了一个点,它之后的所有点就都要取了,所以最佳策略是取出度为0的点。
那么就算做完了。
#include#define F(i,a,b) for(int i=a;i<=(b);++i)#define dF(i,a,b) for(int i=a;i>=(b);--i)#define eF(h,i,u) for(int i=h[u];i;i=nxt[i])using namespace std;int n,m,H,Ans;int Ut[100001];int h[100001],h2[100001],nxt[500001],to[500001],tot;inline void ins(int x,int y){nxt[++tot]=h[x];to[tot]=y;h[x]=tot;}inline void ins2(int x,int y){nxt[++tot]=h2[x];to[tot]=y;h2[x]=tot;}bool vis[100001];int dfn[100001],idf[100001],siz[100001],SCC[100001],Out[100001],cnt,CCn;int h3[100001];inline void ins3(int x,int y){nxt[++tot]=h3[x];to[tot]=y;h3[x]=tot;}bool check(int Ut1,int Ut2){return (Ut2-Ut1+H)%H==1;}void init(){ int x,y; scanf("%d%d%d",&n,&m,&H); F(i,1,n) scanf("%d",Ut+i); F(i,1,m){ scanf("%d%d",&x,&y); if(check(Ut[x],Ut[y])) ins(x,y),ins2(y,x); if(check(Ut[y],Ut[x])) ins(y,x),ins2(x,y); }}void DFS1(int u){ vis[u]=1; eF(h,i,u) if(!vis[to[i]]) DFS1(to[i]); dfn[u]=++cnt; idf[cnt]=u;}void DFS2(int u){ vis[u]=1; SCC[u]=CCn; ++siz[CCn]; ins3(CCn,u); eF(h2,i,u) if(!vis[to[i]]) DFS2(to[i]);}void Kosaraju(){ F(i,1,n) if(!vis[i]) DFS1(i); memset(vis,0,sizeof vis); dF(i,n,1) if(!vis[idf[i]]) ++CCn, DFS2(idf[i]); F(u,1,CCn){ eF(h3,i,u) eF(h,j,to[i]) if(SCC[to[j]]!=u) Out[u]=1; goto ed; ed : ; } siz[Ans=0]=n+1; F(i,1,CCn) if(!Out[i]&&siz[Ans]>siz[i]) Ans=i;}int main(){ init(); Kosaraju(); printf("%d\n",siz[Ans]); eF(h3,i,Ans) printf("%d ",to[i]); return 0;}