@KirinBill
2017-09-18T10:17:07.000000Z
字数 6764
阅读 1701
题解 套题
目录
题目大意:给你一个数列,问是否能通过置换(交换某些元素的位置),使得该数列满足。
#include <cstdio>const int MAXN=1e5+5;int n,cnt_4,cnt_not4;int a[MAXN];int main(){scanf("%d",&n);for(int i=1;i<=n;++i){scanf("%d",&a[i]);if(a[i]%4==0) ++cnt_4;else if(a[i]%2) ++cnt_not4;}if(cnt_4>=cnt_not4 || (cnt_4>=cnt_not4-1 && cnt_4+cnt_not4==n)) printf("Yes");else printf("No");return 0;}
题目大意:给你种颜色,每种有一个数量要求,你要对一个的四连通矩阵染色,使每种颜色数量为,并且每种颜色的方格必须互相连通,给出一种方案。
#include <cstdio>#include <queue>using std::queue;const int MAXHW=105;int n,h,w,a;int sqr[MAXHW][MAXHW];queue<int> q,ans;int main(){scanf("%d%d%d",&h,&w,&n);for(int i=1;i<=n;++i){scanf("%d",&a);q.push(a);}int k=0;while(++k,q.size()){a=q.front();q.pop();for(int i=1;i<=a;++i)ans.push(k);}for(int i=1;i<=h;i+=2){for(int j=1;j<=w;++j){sqr[i][j]=ans.front();ans.pop();}for(int j=w;j && ans.size();--j){sqr[i+1][j]=ans.front();ans.pop();}}for(int i=1;i<=h;++i){for(int j=1;j<=w;++j)printf("%d ",sqr[i][j]);putchar('\n');}return 0;}
题目大意:给你一个数列,每次可以取出相邻的两个数按原数列顺序加到一个新的数列的头部,求字典序最小的新数列。
考试的时候傻掉了。。。
整体不难,但实现起来有些繁琐
#include <cstdio>#include <algorithm>#include <utility>#include <queue>#include <vector>#include <functional>#include <climits>#include <cmath>using std::min;using std::pair;using std::priority_queue;using std::vector;using std::greater;typedef pair<int,int> range;typedef pair<int,int> number;typedef pair<number,range> sub_qry;const int MAXN=2e5+5,MAXLOG=(int)(log(MAXN)/log(2)+0.5);int p[MAXN];class SparseTab{private:int log_tab[MAXN];number c[MAXLOG][MAXN];public:void build(int n,int a[],bool type){log_tab[0]=-1;for(int i=1;i<=n;++i){c[0][i]=number((i&1)==type ? a[i]:INT_MAX,i);log_tab[i]= i&(i-1) ? log_tab[i-1]:log_tab[i-1]+1;}for(int i=1;i<=log_tab[n];++i){for(int j=1;j+(1<<i)-1<=n;++j)c[i][j]=min(c[i-1][j],c[i-1][j+(1<<i-1)]);}}number qry(int l,int r){int k=log_tab[r-l+1];return min(c[k][l],c[k][r-(1<<k)+1]);}}odd,even;inline void solve(int n){static priority_queue<sub_qry,vector<sub_qry>,greater<sub_qry> > hp;number tmp1=odd.qry(1,n),tmp2=even.qry(tmp1.second,n);printf("%d %d ",tmp1.first,tmp2.first);if(1<=tmp1.second-1)hp.push(sub_qry(odd.qry(1,tmp1.second-1),range(1,tmp1.second-1)));if(tmp1.second+1<=tmp2.second-1)hp.push(sub_qry(even.qry(tmp1.second+1,tmp2.second-1),range(tmp1.second+1,tmp2.second-1)));if(tmp2.second+1<=n)hp.push(sub_qry(odd.qry(tmp2.second+1,n),range(tmp2.second+1,n)));sub_qry now;number that;SparseTab *st1,*st2;while(hp.size()){now=hp.top();hp.pop();st1= now.second.first&1 ? &odd:&even;st2= now.second.first&1 ? &even:&odd;that=st2->qry(now.first.second,now.second.second);printf("%d %d ",now.first.first,that.first);if(now.second.first<now.first.second-1)hp.push(sub_qry(st1->qry(now.second.first,now.first.second-1),range(now.second.first,now.first.second-1)));if(now.first.second+1<that.second-1)hp.push(sub_qry(st2->qry(now.first.second+1,that.second-1),range(now.first.second+1,that.second-1)));if(that.second+1<now.second.second)hp.push(sub_qry(st1->qry(that.second+1,now.second.second),range(that.second+1,now.second.second)));}}int main(){int n;scanf("%d",&n);for(int i=1;i<=n;++i)scanf("%d",&p[i]);odd.build(n,p,1),even.build(n,p,0);solve(n);return 0;}
题目大意:有一个无限长的卡片序列标号为,给定个数,这些数对应标号的卡片是向上的,其它为向下的,每次只可以连续翻转奇质数长度的卡片,求使得整个卡片序列都向下的最少操作次数。(,)。
这题太神了,看了半天题解。。。orz
设对取反的最小代价为,其中不一定为质数,现在我们分四种情况讨论:
是奇合数,则有,因为有一个“猜想”(它貌似尚未被完全证明,只能说在这题范围内成立):任意一个奇合数可以表示为3个奇质数之和。
证明:
- 根据维诺格拉多夫定理,任意一个大于5的奇数可以表示为3个质数之和。
- 那么只需证明若一个奇合数能被分解为为奇质数时,它一定能表示为其它3个奇质数之和。
- 将该奇合数写成,考虑当时,不断将,则总有一刻,变为一个奇质数()。
- 又因为哥德巴赫猜想,偶数定能写成两个质数之和(至少在这题数据范围内可以),并且当后,写成的质数和不含2!
- 最后,再考虑时,,7不是奇合数,证毕!(出题人太神了orz)。
,考虑一个质数减去它相邻的比它小的质数等于1,则的情况可以被分解为是质数和偶数两个情况,所以.
#include <cstdio>#include <cmath>#include <climits>#include <queue>#include <algorithm>using std::queue;using std::min;const int MAXX=1e7+5,MAXN=205;int n,cnt_x,cnt_y;int x_id[MAXN],y_id[MAXN];bool up[MAXX];struct node{int he,iter,dis;}d[MAXN];struct line{int to,nex,cap;}ed[MAXN*MAXN<<1];inline bool is_odd_prm(int x){if(x==1) return false;for(int i=2;i*i<=x;++i){if(x%i==0) return false;}return true;}inline void addE(int u,int v,int cap){static int cnt=1;ed[++cnt]=(line){v,d[u].he,cap};d[u].he=cnt;}inline int revE(int i){return i^1;}inline bool BFS(int s,int t,int n){for(int i=1;i<=n;++i)d[i].dis=-1;static queue<int> q;d[s].dis=0;q.push(s);int u;while(q.size()){u=q.front();q.pop();for(int i=d[u].he,v;i;i=ed[i].nex){if(ed[i].cap==0) continue;v=ed[i].to;if(d[v].dis==-1){d[v].dis=d[u].dis+1;q.push(v);}}}return d[t].dis!=-1;}int aug(int u,int rest,const int t){if(u==t) return rest;int ret=0;for(int &i=d[u].iter,v,cap,flow;i;i=ed[i].nex){v=ed[i].to,cap=ed[i].cap;if(d[v].dis!=d[u].dis+1 || cap==0)continue;flow=aug(v,min(cap,rest),t);ed[i].cap-=flow,ed[revE(i)].cap+=flow;ret+=flow,rest-=flow;if(rest==0) return ret;}if(ret==0) d[u].dis=-1;return ret;}inline int Dinic(int s,int t,int n){int ret=0;while(BFS(s,t,n)){for(int i=1;i<=n;++i)d[i].iter=d[i].he;ret+=aug(s,INT_MAX,t);}return ret;}inline void build(){for(int i=1;i<=cnt_x;++i){for(int j=1,v;j<=cnt_y;++j){if(is_odd_prm(abs(x_id[i]-y_id[j]))){v=j+cnt_x;addE(i,v,INT_MAX),addE(v,i,0);}}}for(int i=1,s=cnt_x+cnt_y+1;i<=cnt_x;++i)addE(s,i,1),addE(i,s,0);for(int i=1,u,t=cnt_x+cnt_y+2;i<=cnt_y;++i){u=cnt_x+i;addE(u,t,1),addE(t,u,0);}}int main(){scanf("%d",&n);int x;for(int i=1;i<=n;++i){scanf("%d",&x);up[x]=true;}for(int i=1;i<=x+1;++i){if(up[i]!=up[i-1])i&1 ? x_id[++cnt_x]=i:y_id[++cnt_y]=i;}build();int k=Dinic(cnt_x+cnt_y+1,cnt_x+cnt_y+2,cnt_x+cnt_y+2);printf("%d",k+((cnt_x-k)/2+(cnt_y-k)/2)*2+(cnt_x-k)%2*3);return 0;}