其他分享
首页 > 其他分享> > 高考集训3

高考集训3

作者:互联网

110分

【比赛】2022高考集训3 - 比赛 - 衡中OI (hszxoj.com)

1.单调队列优化DP

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<string>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<iomanip>
#include<bitset>
#include<map>
#include<queue>
#include<bitset>
#include<deque>
#include<vector>
#define _f(i,a,b)  for(register int i=a;i<=b;++i)

#define f_(i,a,b)  for(register int i=a;i>=b;--i)

#define ll long long

#define chu printf


using namespace std;
inline int re()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
const int WR=1001000;ll INF=1e18;
struct firework
{
    int a,b,t;
}fire[400];
ll tmp[160000],f[160000];
int n,m,d;
int l,r;
int que[160000];
int main()
{
    freopen("fire.in","r",stdin);
    freopen("fire.out","w",stdout);
    n=re(),m=re(),d=re();
    _f(i,1,m)
    {
        fire[i].a=re(),fire[i].b=re(),fire[i].t=re();
    }
    for(int i=1;i<=m;i++)//f[i][j]:i烟花在j时刻绽放最大幸福值
    {
        memcpy(tmp,f,sizeof(f));
        int k=1;//当前扩展到的位置 
        ll dis=(ll)(fire[i].t-fire[i-1].t)*d;
        l=1,r=0;//初始为空.....吗? 
        for(int j=1;j<=n;j++)
        {
            while(k<=min((ll)n,j+dis))//最多拓展到的位置
            {
                while(l<=r&&tmp[que[r]]<=tmp[k])r--;//值递减,不然就没有必要要那个que[r]了,离的远还小 
                que[++r]=k;
                k++;
            }
            while(l<r&&j-que[l]>dis)l++;//必须剩下一个,但是是这么剩吗??
             f[j]=tmp[que[l]]+fire[i].b-abs(fire[i].a-j);
        }
     } 
     ll maxans=-INF;
     _f(i,1,n)maxans=max(maxans,f[i]);
     chu("%lld",maxans);
    return 0;
}
/*
DP单调队列优化
满足:
位置单调
多项式中的每一项只和j或者k有关 
f[i][j]=max(f[i-1][k]+summ)
abs(j-k)<=d*(time(i)-time(i-1))
直接枚举k肯定会超时
考虑单调性问题
f[i]固定
在j不断变大的过程中,我肯定是从f[i-1]选择一个位置转移
假设posm,posn
如果posm<posn,f[i-1][posm]<=f[i-1][posn]
 posm一定没用,我就可以扔了
 所以
 枚举n时:维护单调递减的队列 
     拓展新的可能位置(往右边动了多少)
     维护队头合法性(dis能到达)
     对头就是最优解 
*/

2.无脑DP

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<string>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<iomanip>
#include<bitset>
#include<map>
#include<queue>
#include<bitset>
#include<deque>
#include<vector>
#define _f(i,a,b)  for(register int i=a;i<=b;++i)

#define f_(i,a,b)  for(register int i=a;i>=b;--i)

#define ll long long

#define chu printf

#define INF 0x7f7f7f7f
/*说真的,必须向秋英学习
1.样例对了什么都不是,你要把每一个细节抠死,保证代码
过程0问题
2.学会归纳,不是什么都必须记住,但是经常考的必须记住
3.思路灵活不怕麻烦,敢想就敢使劲写 
*/ 
using namespace std;
inline int re()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
const int SIZE=400;
int n,k;
int f[1200][13];
struct city
{
    int to[13][32],sz,rod[13];
} C[13];
inline void DP()
{
    for(int i=0;i<=k+1;i++)
    for(int j=0;j<=n;j++)f[i][j]=INF;
    f[1][1]=0;//初始化,从实际意义考虑 
    _f(i,2,k+1)
    {
        _f(j,1,n)
        {
            _f(kk,1,n)//这里的kk一定不能和上面的重复 
            {
                
                if(j==kk)continue;
            //    if(i==2&&(kk!=1))continue;//第二天只能从第一天转移
            
                int res=(i-1)%C[kk].rod[j];
            //    chu("(%d)modC[%d].rod[%d]:%d    :%d\n",i-1,kk,j,C[kk].rod[j],res);
                if(res==0)res=C[kk].rod[j];//如果res==0,应该是这样而不是==i-1,想清楚 
            //    chu("res:%d\n",res);
                int cost=C[kk].to[j][res];
                if(cost==0)continue;
            //        chu("i:%d\n",i);
                f[i][j]=min(f[i][j],f[i-1][kk]+cost);
            //    if(i==k+1)chu("f[%d][%d]:%d\n",i,j,f[i][j]);
            }
        }
    }
    int answer=f[k+1][n];
    if(answer==INF)chu("0\n");
    else chu("%lld\n",answer);
}
int main()
{
    freopen("perform.in","r",stdin);
    freopen("perform.out","w",stdout);
    while(scanf("%d%d",&n,&k)!=EOF)//n!=0,k!=0
    {
        if(n==0&&k==0)break;
        _f(i,1,n)
        {
            C[i].sz=0;
            _f(j,1,n)
            {
                if(j==i)continue;
                C[i].rod[j]=re();
                _f(k,1,C[i].rod[j])
                {
                    C[i].to[j][k]=re();
                }
            }
        }
        DP();
    }
    return 0;
}
/*
3 6
2 130 150
3 75 0 80
7 120 110 0 100 110 120 0
4 60 70 60 50
3 0 135 140
2 70 80
2 3
2 0 70
1 80
3 6
2 130 150
3 75 0 80
7 120 110 0 100 110 120 0
4 60 70 60 50
3 0 135 140
2 70 80
0 0

3 10
5 1 1 1 1 1
5 1 1 1 1 1
5 1 1 1 1 1
5 1 1 1 1 1
5 1 1 1 1 1
5 1 1 1 1 1
*/

3.图论的相关知识+思维

学会自己找性质和结论

const int SIZE=400;
const int WR=1001000;
int n,aim[WR];
int ipt[WR];
int lve,sze;
int que[WR],pos;
bool kill[WR],exist[WR];
int main()
{
    freopen("maf.in","r",stdin);freopen("maf.out","w",stdout);
    n=re();
    _f(i,1,n)aim[i]=re(),ipt[aim[i]]++;
    _f(i,1,n)
    {
        if(ipt[i]==0)
        {
            lve++;que[++sze]=i;
        }
    }
    pos=1;
    while(pos<=sze)
    {
        int frnt=que[pos];//取出那个(起初)一定是不死 
        pos++;
        if(kill[aim[frnt]])continue;//如果不死神的目标死了,走掉 
        kill[aim[frnt]]=true;
        int targ=aim[aim[frnt]];//不死神的目标的目标,目标一定死,目标的目标不一定 
        ipt[targ]--;//假如目标死了,那targ当前就成了不死神2 
        exist[targ]=true;//是被救的 
        if(!ipt[targ])que[++sze]=targ; 
    }
    _f(i,1,n)
    {
        if(ipt[i]&&!kill[i])
        {
            int ring=0;
            bool flag=false;
            for(int j=i;!kill[j];j=aim[j])
            {
                ring++;
                if(exist[j])flag=true;
                kill[j]=true;
            }
            if(!flag&&ring>1)lve++;//排除自环 
            sze+=ring/2;
        }
    }
    chu("%d %d",n-sze,n-lve);
    return 0;
}

4.结论+固定条件+简单唯一枚举

const int SIZE=400;
bool zhen[5][5];
bool fuben[5][5];int tot;
inline void cpy()
{
    _f(i,1,4)
    {
        _f(j,1,4)zhen[i][j]=fuben[i][j];
    }
}
char s[5][5];
inline void maketurn(int x,int y)
{
    tot++;
    zhen[x+1][y]=!zhen[x+1][y];
    zhen[x-1][y]=!zhen[x-1][y];
    zhen[x][y-1]=!zhen[x][y-1];
    zhen[x][y+1]=!zhen[x][y+1];
    zhen[x][y]=!zhen[x][y];
}
int minans=INF;
inline bool check(bool p)
{
    _f(i,1,4)
    {
        _f(j,1,4)
        if(zhen[i][j]!=p)return false;
    }
    return true;
}

int main()
{
    freopen("flip.in","r",stdin);    freopen("flip.out","w",stdout);
    _f(i,1,4)
    {
        scanf("%s",s[i]+1);
        int dieC=0;
        _f(j,1,4)
        {
            if(s[i][j]=='w')zhen[i][j]=1,fuben[i][j]=1;
            //chu("%d ",zhen[i][j]);
        }
    //    chu("\n");
    }
    //枚举操作数,如果翻转就是1,不反转就是0
    _f(i,0,15)
    {
        cpy();
        tot=0;
        //i是操作就要干 
        _f(j,1,4)
        {
            if(i&(1<<(j-1)))
            {
                maketurn(1,j);
            }
        }
        //第一行
        _f(j,1,4)
        {
            if(zhen[1][j]!=0)maketurn(2,j);//先都变成0
        } 
        _f(j,1,4)//第二行
        {
            if(zhen[2][j]!=0)maketurn(3,j);
         } 
        _f(j,1,4)//第三行
        {
            if(zhen[3][j]!=0)maketurn(4,j);    
        } 
        if(check(0))minans=min(minans,tot);
    } 
    _f(i,0,15)
    {
        cpy();
        tot=0;
        //i是操作就要干 
        _f(j,1,4)
        {
            if(i&(1<<(j-1)))
            {
                maketurn(1,j);
            }
        }
        //第一行
        _f(j,1,4)
        {
            if(zhen[1][j]!=1)maketurn(2,j);//先都变成0
        } 
        _f(j,1,4)//第二行
        {
            if(zhen[2][j]!=1)maketurn(3,j);
         } 
        _f(j,1,4)//第三行
        {
            if(zhen[3][j]!=1)maketurn(4,j);    
        } 
    //    chu("isok?\n");
    //    chu("check:%d\n",check(1));
    //    chu("minans:%d  tot:%d\n",minans,tot);
        if(check(1))minans=min(minans,tot);
    } 
    if(minans==INF)chu("Impossible");
    else chu("%d",minans);
    return 0;
}
/*
枚举的前提是知道性质:
1.当第一行确定翻转,后面的反转方案唯一
2.反转顺序无所谓
3每个点如果反转超过1次即无解
枚举第一行状态
然后
枚举1 2,3 4
x,y==1,必须让x+1,y反转 
*/

 

标签:ch,int,高考,zhen,WR,include,集训,define
来源: https://www.cnblogs.com/403caorong/p/16356850.html