@KirinBill
2017-09-18T18:17:07.000000Z
字数 6764
阅读 1229
题解
套题
目录
题目大意:给你一个数列,问是否能通过置换(交换某些元素的位置),使得该数列满足。
#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;
}