多校联考6
rank41 mark146
不可掉以轻心,仍有许多不足
T1:大模拟,非常考验码力和现实模拟转化代码思维
T2/T3:思维题
T4:图论
T1大暴力
塔牌游戏
技巧:
1如果比较复杂的字符串操作识别,可以转化成ax+b的(a,b)表达式进行操作,用map映射就行
2对于优先级顺序选择,可以先分开算(用数组下标)再合起来
3.map很灵活,可以用一个字符串映射一个点对mp[s]=op;op.first,op.second
#include<bits/stdc++.h> #define up(l,r,i) for(int i=l;i<=r;++i) using namespace std; const int INF=2e9,NN=30+3,KK=1e6+3; const string TR="TURN",DB="DOUBLE",PS="PASS"; int n,m,k,o=1,d,p,h=100,kk=0; string N[NN],K[KK],c; bool f; unordered_map <string,pair<double,double>> M; unordered_map<string,int> H[NN]; enum{ADD=0,MIN,MUL,DIV,SET}; bool del(string c){ if(!H[o][c]) return 0; cout<<N[o]<<" used "<<c<<",now p="<<p<<".\n",--H[o][c],H[o][K[++kk]]++; return 1; } #define f(x) if(v?W[x]>w:W[x]<w)w=W[x],r=x; bool useA(bool v){ int W[5],r,t,y,w=v?-INF:INF; string F[5],s; fill(W,W+5,w); bool e=1; for(auto x:H[o]) if((s=x.first)!=TR&&s!=DB&&s!=PS&&x.second){ t=s[0]-'A',y=floor(M[s].first*p+1e-9+M[s].second); if(y<h&&(v?y>W[t]:y<W[t])) W[t]=y,F[t]=s,e=0; } // for(auto x=H[o].begin();x!=H[o].end();++x) if(v){ if(W[MUL]>w) w=W[MUL],r=MUL; if(W[ADD]>w) w=W[ADD],r=ADD; if(W[MIN]>w) w=W[MIN],r=MIN; if(W[DIV]>w) w=W[DIV],r=DIV; if(W[SET]>w) w=W[SET],r=SET; } else{ if(W[DIV]<w) w=W[DIV],r=DIV; if(W[MIN]<w) w=W[MIN],r=MIN; if(W[ADD]<w) w=W[ADD],r=ADD; if(W[MUL]<w) w=W[MUL],r=MUL; if(W[SET]<w) w=W[SET],r=SET; } //我开始没有想到的怎么保证使用牌的时候,* + - /的优先顺序,这里就巧妙解决 //用M[]:数组下标表示+ -*/(ABCD),每一种结果单独算,最后按照优先级顺序比较就行 if(e) return 0; p=w,del(F[r]),f=0; return 1; } bool useB(){ if(del(PS)) return 1; if(del(TR)) {d=-d; return 1;} if(del(DB)) {f=1;return 1;} return 0; } #define g(a,b,c) M[a]=make_pair(b,c) int main(){ g("A1" ,1, 1);g("A2" , 1, 2);g("A5",1, 5);g("A9" ,1, 9);g("A19",1, 19); g("A49",1,49);g("A99", 1,99);g("B1",1,-1);g("B9" ,1,-9);g("B19",1,-19); g("C2" ,2, 0);g("D2" ,0.5, 0);g("E0",0, 0);g("E49",0,49);g("E99",0, 99); cin>>n>>m>>k; up(1,n,i){cin>>N[i]; up(1,3,j) cin>>c,++H[i][c]; } up(1,k,i) cin>>K[i]; up(1,m,i){ cout<<"Round "<<i<<":\n",d=1,p=f=0; while(1) { if(!f) goto L1;//如果没有double效果,直接去正常 if(useB()) goto L2; //如果double诅咒了,还好可以用特殊牌 if(!useA(0)) break;//没有特殊牌,就只能试试普通,普通不行就输了 L1: if(!useA(1)&&!useB()) break;//普通牌和特殊牌都不能用(一定输) L2: o+=d; if(o==n+1) o=1; if(!o) o=n; } cout<<N[o]<<" lost the game.\n"; H[o].clear(); up(0,2,j) H[o][K[++kk]]++; } //printf("%d %d %d %d %d",ADD,MIN,MUL,DIV,SET); return 0; } /* H[i][j]=k:i号玩家拥有“j”牌的数量 */
T2:
给你长度为2*n的字符串s1,s2,s3,进行复制接成长度4*n的字符串:abba->abbaabba
问长度为2*n+1的公共子序列是(串只有g/z)
构造思维:1--2*n有n个g,2*n+1--4*n有n个z,假如最后一个是g,一定合法
假如最后一个是z,那2*n个也是z,补上
所以g(n)+z(n)+g就可以是答案
T3
没什么好说的
T4
给你n个点,n-1条树边,m-n+1条返祖边,求Q个询问,任意两点最短路
求最短路,没什么比dijstra更优秀的了,任意的话n^2logn
只能考虑特殊性质
如果是树,那么dis[i][j]用简单的lca+分类讨论就能解决(dis[x]表示x到根的距离,dis[fax]-dis[x]就是路径上的)
如果是在树上+了返祖边,那么更短路只能是从u-->lca->add_dot-->lca-->v去更新
其中,add_dot是lca的祖先,最多只有30条(吐槽,明明题目说20条)
完全可以直接暴力枚举
考虑求出任意两点最短路
dis[x][y]肯定开不下
但是我们只需要用到从x到它的祖先的distance,所以最多只有n*30空间就够了
在算的时候,我们dfs求出任意一个rt节点的封闭子树内子节点到rt的最短距离,vis[]打一下标记
dij搞
dij:
多次入队,一次松弛
vis[]标记节点是否已经松弛过其他节点
注意priority默认是大根堆,所以要+负数距离!!!
spfa
多次入队,多次松弛
vis[]标识是否当前在队里
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<ctime> #include<cmath> #include<iomanip> #include<algorithm> #include<bitset> #include<map> #include<vector> #include<deque> #include<queue> #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 INF 2147483647 #define chu printf #define ll long long #define ull unsigned long long using namespace std; inline int re() { int x=0,h=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-')h=-1; ch=getchar(); } while(ch<='9'&&ch>='0') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x; } const int N=3000000+10,MOD=1; struct TREE { int to,nxt,w; }et[1000000+10],ed[1000000+10];//1e5个点,5e5条边 int tot1,tot2,head1[100000+10],head2[100000+10]; bool vis[100000+10],can[100000+10][33]; int top[100000+10],dep[100000+10],fa[100000+10],siz[100000+10]; int n,m,q; ll dis[100000][33]; priority_queue< pair<ll,int> >que; inline void add_tree(int x,int y,int val) { et[++tot1].to=y,et[tot1].nxt=head1[x],head1[x]=tot1;et[tot1].w=val; } inline void add_d(int x,int y,int val) { ed[++tot2].to=y,ed[tot2].nxt=head2[x],head2[x]=tot2;ed[tot2].w=val; } inline void dfs(int x,int f) { fa[x]=f;siz[x]=1; for(register int i=head1[x];i;i=et[i].nxt) { int to=et[i].to; if(to==f)continue; dep[to]=dep[x]+1; dfs(to,x); siz[x]+=siz[to]; } } inline void slpf(int x,int belong) { int son=0; top[x]=belong; for(register int i=head1[x];i;i=et[i].nxt) { int to=et[i].to; if(to==fa[x])continue; if(siz[son]<siz[to])son=to; } if(son)slpf(son,belong); for(register int i=head1[x];i;i=et[i].nxt) { int to=et[i].to; if(!top[to])slpf(to,to); } } inline int LCA(int x,int y) { while(top[x]!=top[y]) { //chu("dsfd\n"); if(dep[top[x]]<dep[top[y]])//x在上边 { y=fa[top[y]]; } else x=fa[top[x]]; } if(dep[x]>dep[y])return y; return x; } inline void dijstra(int x) { //dis[] dis[x][0]=0; // can[x][0]=1; que.push(make_pair(0,x)); pair<int,int>ato; while(!que.empty()) { ato=que.top(); que.pop(); if(can[ato.second][dep[ato.second]-dep[x]])continue; can[ato.second][dep[ato.second]-dep[x]]=1; //vis[ato]=1; for(register int i=head2[ato.second];i;i=ed[i].nxt) { int to=ed[i].to; if(vis[to])continue;//不在x子树内 if(dis[to][dep[to]-dep[x]]>dis[ato.second][dep[ato.second]-dep[x]]+(ll)ed[i].w) { dis[to][dep[to]-dep[x]]=dis[ato.second][dep[ato.second]-dep[x]]+(ll)ed[i].w; que.push(make_pair(-dis[to][dep[to]-dep[x]],to)); } } } } inline void dfs_dij(int x) { //先跑然后再vis=1 dijstra(x); vis[x]=1; for(int i=head1[x];i;i=et[i].nxt) { int to=et[i].to; if(to==fa[x])continue; dfs_dij(to); } } int main() { // freopen("reverse1.out","r",stdin); n=re(),m=re(),q=re(); //chu("(fac)%d %d %d\n",n,m,q); _f(i,1,n-1) { // chu("i:%d\n",i); int x=re(),y=re(),val=re(); add_tree(x,y,val); add_tree(y,x,val); add_d(x,y,val);add_d(y,x,val); } // chu("1out"); for(register int i=n;i<=m;++i) { int x=re(),y=re(),val=re();add_d(x,y,val);add_d(y,x,val); } _f(i,1,n) { _f(j,1,30)dis[i][j]=1e18; } // chu("out"); dep[1]=1; dfs(1,0);//先处理一把dep //chu("out\n"); slpf(1,1); dfs_dij(1); _f(i,1,q) { int u=re(),v=re(); if(dep[u]>dep[v])swap(u,v); int lca=LCA(u,v); if(lca==u) { ll dismi=dis[v][dep[v]-dep[u]]; while(fa[lca]) { lca=fa[lca]; dismi=min(dismi,dis[v][dep[v]-dep[lca]]+dis[u][dep[u]-dep[lca]]); } chu("%lld\n",dismi); } else { ll dismi=dis[v][dep[v]-dep[lca]]+dis[u][dep[u]-dep[lca]]; // chu("(lca:%d)dismi:%lld\n",lca,dismi); while(fa[lca]) { lca=fa[lca]; // chu("try:%d\n",lca); dismi=min(dismi,dis[v][dep[v]-dep[lca]]+dis[u][dep[u]-dep[lca]]); } chu("%lld\n",dismi); } } return 0; } /* dis[i][j]:i到他的j级父节点的最短路(j<=20) dfs():树 dep[x],LCA(x,y)//用原图去搞 每个子节点跑dij,vis 无向图缩点!!复习!!! 6 8 2 1 6 3 1 2 3 5 4 3 1 3 3 6 5 3 2 5 1 2 3 7 1 4 1 3 5 5 1 */
最短路,没什么