[Poi2015]

[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;
}

[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;
}

时间: 2024-09-29 08:48:15

[Poi2015]的相关文章

bzoj 4385: [POI2015]Wilcze do?y

4385: [POI2015]Wilcze do?y Description 给定一个长度为n的序列,你有一次机会选中一段连续的长度不超过d的区间,将里面所有数字全部修改为0.请找到最长的一段连续区间,使得该区间内所有数字之和不超过p. Input 第一行包含三个整数n,p,d(1<=d<=n<=2000000,0<=p<=10^16).第二行包含n个正整数,依次表示序列中每个数w[i](1<=w[i]<=10^9). Output 包含一行一个正整数,即修改后能

BZOJ 3747: [POI2015]Kinoman( 线段树 )

线段树... 我们可以枚举左端点 , 然后用线段树找出所有右端点中的最大值 . ----------------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( i

【BZOJ 3747】 3747: [POI2015]Kinoman (线段树)

3747: [POI2015]Kinoman Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 830  Solved: 338 Description 共有m部电影,编号为1~m,第i部电影的好看值为w[i]. 在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部. 你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,-,r天内所有的电影.如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值

【BZOJ4378】[POI2015]Logistyka 树状数组

[BZOJ4378][POI2015]Logistyka Description 维护一个长度为n的序列,一开始都是0,支持以下两种操作:1.U k a 将序列中第k个数修改为a.2.Z c s 在这个序列上,每次选出c个正数,并将它们都减去1,询问能否进行s次操作.每次询问独立,即每次询问不会对序列进行修改. Input 第一行包含两个正整数n,m(1<=n,m<=1000000),分别表示序列长度和操作次数.接下来m行为m个操作,其中1<=k,c<=n,0<=a<=

BZOJ 4384: [POI2015]Trzy wie?e

4384: [POI2015]Trzy wie?e Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 217  Solved: 61[Submit][Status][Discuss] Description 给定一个长度为n的仅包含'B'.'C'.'S'三种字符的字符串,请找到最长的一段连续子串,使得这一段要么只有一种字符,要么有多种字符,但是没有任意两种字符出现次数相同. Input 第一行包含一个正整数n(1<=n<=1000000),表示字符

【BZOJ3747】[POI2015]Kinoman 线段树

[BZOJ3747][POI2015]Kinoman Description 共有m部电影,编号为1~m,第i部电影的好看值为w[i]. 在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部. 你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,…,r天内所有的电影.如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值.所以你希望最大化观看且仅观看过一次的电影的好看值的总和. Input 第一行两个整数n,m(1<=m<=n&

洛谷P3588 - [POI2015]Pustynia

Portal Description 给定一个长度为\(n(n\leq10^5)\)的正整数序列\(\{a_n\}\),每个数都在\([1,10^9]\)范围内,告诉你其中\(s\)个数,并给出\(m(m\leq2\times10^5)\)条信息.每条信息包含三个数\(L,R,k(Σk\leq 3\times10^5)\)以及\(k\)个正整数\(\{x_k\}\),表示\(a_L..a_R\)中,任意一个\(x\)均比剩下的\(R-L+1-k\)个数大(严格大于,即没有等号).请任意构造出一组

[bzoj3747][POI2015]Kinoman_线段树

Kinoman bzoj-3747 POI-2015 题目大意:有m部电影,第i部电影的好看值为w[i].现在放了n天电影,请你选择一段区间l~r使得l到r之间的好看值总和最大.特别地,如果同一种电影放了两遍及以上,那么这种电影的好看值将不会被获得. 注释:$1\le m \le n \le 10^6$. 想法:和rmq problem类似的,我们处理出每一个位置pos右边第一个和pos上电影种类相同的位置nxt[pos].然后,我从1-n扫一遍,每次讲l+1到nxt[l]-1之间的值加上w[a

bzoj [POI2015]Myjnie

[POI2015]Myjnie Time Limit: 40 Sec Memory Limit: 256 MBSec Special Judge Description 有n家洗车店从左往右排成一排,每家店都有一个正整数价格p[i]. 有m个人要来消费,第i个人会驶过第a[i]个开始一直到第b[i]个洗车店,且会选择这些店中最便宜的一个进行一次消费.但是如果这个最便宜的价格大于c[i],那么这个人就不洗车了. 请给每家店指定一个价格,使得所有人花的钱的总和最大. Input 第一行包含两个正整数