高考集训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