08-18考试总结

08-18考试总结

唉,本来可以 AK 的

0818可爱精灵宝贝

  • 考验状态设计和预处理的区间 DP 题
  • 状态设计几乎和关路灯完全一样
  • 也是以人的位置,对状态分类
  • 分为人在左端点,人在右端点
  • 然鹅考试
  • 剩下的代码里有
/*************************************************************************
    > File Name: Pokemon.cpp
    > Author: Typedef 
    > Mail: 1815979752@qq.com 
    > Created Time: 2021-08-18 15:52:02
    > blog: https://www.cnblogs.com/Illyasviel
 ************************************************************************/
#include<bits/stdc++.h>
using namespace std;
const int N=2e3+7,M=1e2+7;
struct Node{
    int pos,val;
    int t;
}p[N];
int f[N][M][M][2];
int n,m,k;
int res=0;
int tlim;
int s;
bool cmp(Node a,Node b){
    return a.pos<b.pos;
}
template<class T>void qread(T &x){
    x=0;bool f=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    if(f) x=-x;
}
int main(){
//出屎化
    memset(f,128,sizeof(f));
    qread(n),qread(k),qread(m);
    for(int i=1;i<=m;i++){
        int a,b,t;
        qread(a),qread(b),qread(t);
        p[i]={a,b,t};
        tlim=max(t,tlim);
    }
//出屎节点
    p[++m]={k,0,tlim};
    sort(p+1,p+m+1,cmp);
    for(int i=1;i<=m;i++) if(p[i].pos==k&&!p[i].val) s=i;
    f[0][s][s][0]=f[0][s][s][1]=0;
//预处理左半部分
    for(int i=s-1;i>;i--){
        int now=abs(p[s].pos-p[i].pos),pre=abs(p[s].pos-p[i+1].pos);
        f[now][i][s][0]=f[pre][i+1][s][0];
        if(now<p[i].t) f[now][i][s][0]+=p[i].val;
        res=max(res,f[now][i][s][0]);
    }
//预处理右半部分
    for(int i=s+1;i<=m;i++){
        int now=abs(p[i].pos-p[s].pos),pre=abs(p[i-1].pos-p[s].pos);
        f[now][s][i][1]=f[pre][s][i-1][1];
        if(now<p[i].t) f[now][i][s][1]+=p[i].val;
        res=max(res,f[now][s][i][1]);
    }
//合并区间DP
    for(int t=1;t<=tlim;t++)
        for(int l=1;l<=s-1;l++)
            for(int r=s+1;r<=m;r++){
                int tback=abs(p[r].pos-p[l].pos),tl=abs(p[l+1].pos-p[l].pos),tr=abs(p[r].pos-p[r-1].pos);
                f[t][l][r][0]=max(f[max(t-tl,0)][l+1][r][0],f[max(t-tback,0)][l+1][r][1])+((t<p[l].t)?p[l].val:0);
                f[t][l][r][1]=max(f[max(t-tr,0)][l][r-1][1],f[max(t-tback,0)][l][r-1][0])+((t<p[r].t)?p[r].val:0);
                res=max(res,max(f[t][l][r][0],f[t][l][r][1]));
            }
    printf("%d",res);
    return 0;
}

0818最短路(path)

  • 思路还是比较简单的
  • 首先你以所有必经点(包括起点、终点)为原点,跑最短路
  • 求得两两必经点间的距离
  • 然后在必经点上跑爆搜,不会 T
/*************************************************************************
    > File Name: shortestpath.cpp
    > Author: Typedef 
    > Mail: 1815979752@qq.com 
    > Created Time: 2021-08-18 17:37:26
    > blog: https://www.cnblogs.com/Illyasviel
 ************************************************************************/
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+7,M=2e5+7;
int tot=0;
int n,m,s;
int head[N];
long long d[N];
bool v[N];
priority_queue<pair<long long,int> > q;
inline int redn(){
    int ret=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();}
    while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
    return ret*f;
}
inline long long redl(){
    long long ret=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();}
    while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
    return ret*f;
}
struct edge{
    int ver,next;
    long long len;
}e[M];
void add(int x,int y,long long z){
    e[++tot].ver=y;
    e[tot].len=z;
    e[tot].next=head[x];
    head[x]=tot;
}
int dist[13][13];
int S,T,k;
int p[14];
bool vis[14];
int ans=2147483647;
void dijkstra(int s,int id){
    memset(v,0,sizeof(v));
    for(register int i=1;i<=n;i++){
        d[i]=2147483647;
    }
    d[s]=0;
    q.push(make_pair(0,s));
    while(!q.empty()){
        int x=q.top().second;
        q.pop();
        if(v[x])
            continue;
        for(register int i=head[x];i;i=e[i].next){
            int y=e[i].ver,z=e[i].len;
            if(d[y]>d[x]+z){
                d[y]=d[x]+z;
                q.push(make_pair(-d[y],y));
                v[x]=1;
            }
        }
    }
    for(int i=0;i<=k+1;i++){
        if(i==id) continue;
        dist[id][i]=d[p[i]];
    }
}
vector<int> path;
void solve(int step){
    if(step==k+1){
        int res=0,fl=0;
        path.push_back(k+1);
        for(int i=1;i<k+2;i++){
            if(dist[path[i-1]][path[i]]==2147483647){
                fl=1;
                break;
            }
            res+=dist[path[i-1]][path[i]];
        }
        path.clear();
        if(fl) return;
        else{
            ans=min(ans,res);
            return;
        }
    }
    for(int i=1;i<=k;i++){
        if(vis[i]) continue;
        vis[i]=1;
        path.push_back(i);
        solve(step+1);
        path.pop_back();
        vis[i]=0;
    }
}
signed main(){
    scanf("%lld%lld%lld%lld%lld",&n,&m,&k,&S,&T);
    for(register int i=1;i<=m;i++){
        int x,y;
        long long z;
        x=redn();
        y=redn();
        z=redl();
        add(x,y,z);
    }
    for(int i=1;i<=k;i++) scanf("%lld",&p[i]);
    p[0]=S,p[k+1]=T;
    for(int i=0;i<=k+1;i++)
        dijkstra(p[i],i);
    path.push_back(0);
    solve(1);
    if(ans==2147483647) puts("-1");
    else printf("%lld\n",ans);
    return 0;
}

0818剑与魔法(dragons)

  • 首先对事件按返回事件分段
  • 求出每一段的限制数量,把这一段的塞进堆里,取出前几个
  • 记得最后一段特判,最后一个要求不必满足
/*************************************************************************
    > File Name: SwordAndMagic.cpp
    > Author: Typedef 
    > Mail: 1815979752@qq.com 
    > Created Time: 2021-08-18 14:07:08
    > blog: https://www.cnblogs.com/Illyasviel
 ************************************************************************/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>void qread(T &x){
    x=0;bool f=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    if(f) x=-x;
}
char op[3];
ll ans;
ll n,t;
ll tot,idx;
priority_queue<ll,vector<ll>,greater<ll> > q;
signed main(){
    qread(n);
    for(int i=1;i<=n;i++){
        scanf("%s",op);
        qread(t);
        if(i==n){
            tot=t;
            break;
        }
        if(*op=='c') q.push(t);
        else while(q.size()>=t) q.pop();
    }
    while(!q.empty()) ans+=q.top(),q.pop(),idx++;
    if(idx<tot) puts("-1");
    else printf("%lld\n",ans);
    return 0;
}

0818三角形(triangle)

  • 在插入点的同时,考虑新增的三角形
  • 首先插入新增的线,按斜率排序
  • 然后 总 \(-\) 不和法 得到合法的
  • 不合法的就是斜率相同的组成的那些
/*************************************************************************
    > File Name: CountingTrangles.cpp
    > Author: Typedef 
    > Mail: 1815979752@qq.com 
    > Created Time: 2021-08-18 15:05:03
    > blog: https://www.cnblogs.com/Illyasviel
 ************************************************************************/
#include<bits/stdc++.h>
#define INF 0x7fffffff
using namespace std;
typedef long long ll;
const int N=2e6+7;
ll x[N],y[N];
double k[N];
template<class T>void qread(T &x){
    x=0;bool f=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    if(f) x=-x;
}
ll cnt,idx;
ll res=0;
ll n;
double get_k(ll X1,ll Y1,ll X2,ll Y2){
    return (1.0*(double)(Y1-Y2))/(1.0*(double)(X1-X2));
}
int main(){
    qread(n);
    for(int i=1;i<=n;i++){
        qread(x[i]),qread(y[i]);
        idx=0;
        for(int j=i-1;j;j--){
            if(x[i]==x[j]) k[++idx]=INF;
            else k[++idx]=get_k(x[i],y[i],x[j],y[j]);
        }
        sort(k+1,k+idx+1);
        cnt=1;
        for(int j=2;j<=idx;j++){
            if(k[j]==k[j-1]) cnt++;
            else res+=cnt*(cnt-1)>>1,cnt=1;
        }
        res+=cnt*(cnt-1)>>1;
    }
    printf("%lld\n",n*(n-1)*(n-2)/6-res);
    return 0;
}
posted @ 2021-08-18 22:11  actypedef  阅读(56)  评论(2)    收藏  举报