码迷,mamicode.com
首页 > 其他好文 > 详细

[Poi2015]

时间:2016-09-01 21:37:38      阅读:242      评论:0      收藏:0      [点我收藏+]

标签:

 

 

[POI2015]?asuchy

一看以为是sb题 简单来说就是每个人获得热量要尽量多 不能找别人

首先这道题好像我自己找不到NIE的情况

很容易想到一个优化 如果一个数/2>另一个数 那么一定选这个数

然后我想着其他的话就随便分配一个 然后会得出下一个 其实这样做是错的 因为你选完之后不知道下一个会不会是来降低我当前选的那一个的热量使得我当前的原来最优变成不是最优

 

然后这样子 怎么办呢??? 废话 膜题解

 

膜拜Claris 我们既然不知道下一个会不会来降低热量 不妨把每个食物的状态都定下来 让它们去dp下一个合法的状态

定义F[i][0-3]表示当前食物 0是两边都不选它 1是左边选 2是右边选 3是都选

那么的话而且保证已经解决i-1个 记录前驱的状态是什么

 

但是有一个细节 就是1和N的处理 我是把1再插后面 枚举食物1的状态 如果最后面的1还能维持原来的状态很明显合法

技术分享
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define Maxn 1000010
using namespace std;
int F[Maxn][4]; int N,C[Maxn]; int ans[Maxn];
void Do(int last)
{
  for(int i=N-1;i>=1;i--)
  {
     if(last==1) ans[i-1]=i;
     else if(last==2) ans[i]=i;
     else if(last==3) ans[i-1]=ans[i]=i;
     last=F[i][last];
  }
  for(int i=1;i<N-1;i++) printf("%d ",ans[i]); printf("%d\n",ans[N-1]);
}

void DP()
{
  for(int i=2;i<=N;i++)
  {
    if((F[i-1][2]!=-1)&&(C[i-1]>=C[i])) F[i][0]=2;
    if((F[i-1][3]!=-1)&&(C[i-1]>=(C[i]*2))) F[i][0]=3;
    
    if((F[i-1][0]!=-1)&&(C[i-1]<=C[i])) F[i][1]=0;
    if((F[i-1][1]!=-1)&&(C[i-1]<=(C[i]*2))) F[i][1]=1;
    
    if((F[i-1][2]!=-1)&&((C[i-1]*2)>=C[i])) F[i][2]=2;
    if((F[i-1][3]!=-1)&&(C[i-1]>=C[i])) F[i][2]=3;

    if((F[i-1][0]!=-1)&&((C[i-1]*2)<=C[i])) F[i][3]=0;
    if((F[i-1][1]!=-1)&&(C[i-1]<=C[i])) F[i][3]=1;     
  }
}
int main()
{
  //freopen("a.in","r",stdin);
  //freopen("a.out","w",stdout);
  scanf("%d",&N);
  for(int i=1;i<=N;i++) scanf("%d",&C[i]); N++; C[N]=C[1];
  
  memset(F,-1,sizeof(F)); F[1][3]=1;
  DP();
  if(F[N][3]!=-1){ans[1]=1; ans[N-1]=1; Do(F[N][3]); return 0;}
  
  memset(F,-1,sizeof(F)); F[1][1]=1;
  DP();
  if(F[N][1]!=-1){ans[1]=2; ans[N-1]=1; Do(F[N][1]); return 0;}
  
  memset(F,-1,sizeof(F)); F[1][2]=1;
  DP();
  if(F[N][2]!=-1){ans[1]=1; ans[N-1]=N; Do(F[N][2]); return 0;}
  
  memset(F,-1,sizeof(F)); F[1][0]=1;
  DP();
  if(F[N][0]!=-1){ans[1]=2; ans[N-1]=N; Do(F[N][0]); return 0;}
  printf("NIE\n");
  return 0;
}
View Code

 

 

[POI2015]Piecz??

题目的意思是要你用印章把原图的x盖满 枚举左上方的点和印章左上方的点对应 本来想写链表优化的 却发现没有我的暴力优...

然后复了一个读入优化 谢谢

技术分享
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<vector>
#define Maxn 1010
using namespace std;
pair<int,int> Q[Maxn*Maxn]; int tail;
int N,M; int A,B; int Tcase;
int str[Maxn][Maxn]; int st[Maxn][Maxn]; bool bo[Maxn][Maxn];
inline int cread() {  
    char ch = getchar(); for(; ch != x && ch != .; ch = getchar());  
    return ch == x;  
}  
int main()
{
  //freopen("a.in","r",stdin);
  //freopen("a.out","w",stdout);
  scanf("%d",&Tcase);
  while(Tcase--)
  {
    scanf("%d%d%d%d",&N,&M,&A,&B);
    for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) str[i][j]=cread();
    for(int i=0;i<A;i++) for(int j=0;j<B;j++) st[i][j]=cread();
    
    pair<int,int>ST;
    
    bool bk=false;
    for(int i=0;i<A;i++){for(int j=0;j<B;j++) if(st[i][j]){ST=make_pair(i,j); bk=true; break;} if(bk) break;}
    tail=0; for(int i=0;i<A;i++) for(int j=0;j<B;j++) if(st[i][j]){Q[++tail]=make_pair(i-ST.first,j-ST.second);}
     
    memset(bo,0,sizeof(bo)); for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) if(str[i][j]) bo[i][j]=1; 
     
    bk=true;
    for(int i=1;i<=N;i++)
    {
      for(int j=1;j<=M;j++)
      {
        if(bo[i][j])
        {
          int k;
          for(k=1;k<=tail;k++)
          {
            if((i+Q[k].first>N)||(j+Q[k].second>M)) break;
            if(!bo[i+Q[k].first][j+Q[k].second]) break;
            bo[i+Q[k].first][j+Q[k].second]=0;
          }
          if(k!=tail+1){bk=false; break;}
        }
      }
      if(!bk) break;
    }
    if(!bk) printf("NIE\n");
    else printf("TAK\n");
  }
  return 0;
}
View Code

 

[Poi2015]

标签:

原文地址:http://www.cnblogs.com/wohenshuai/p/5831238.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!