多校联考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


*/
View Code

 

最短路,没什么

 

posted on 2022-07-26 18:56  HZOI-曹蓉  阅读(26)  评论(0编辑  收藏  举报