《2018 Multi-University Training Contest 7》

Age of Moyu:

这个题只要看到隐藏的一个线索就可以做了。

因为这里的权值都是1,如果当前有一种方案最短路大于原先的,但是可以增加一种新颜色,这样也不需要加入,因为我们到了u点后,到后面都是需要变成他的后继边里的某一边且只需要花费1的代价。

所以对于大于的方案就可以省去。

但是可能存在多个最短路距离一样颜色不用的情况,所以我们可以用set记录每个点最短距离包含的颜色数,来更行。

这里用spfa来更快,因为标记一下,如果在队列里没更新到,那么因为我们已经插入到set里了,就不需要再放入队列了。

这题还有好多玄学问题。。两个初始化位置从1开始就超时,一定要从0开始。而且快读被卡掉了。。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,set<int>> pii;
const int N = 1e5 + 5;
const int M = 1e5 + 5;
const LL Mod = 199999;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    void print(int x){
        if(x < 0){x = -x;putchar('-');}
        if(x > 9) print(x/10);
        putchar(x%10+'0');
    }
}
using namespace FASTIO;

int n,m;
typedef pair<int,int> pt;
struct Node{int to,col;};
vector<Node> G[N];
pii dis[N];
bool vis[N];
void solve() {
    queue<int> Q;
    for(int i = 0;i <= n;++i) dis[i].first = INF,dis[i].second.clear();
    dis[1].first = 0;
    Q.push(1);
    while(!Q.empty()) {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;
        for(auto v : G[u]) {
            int cost = (dis[u].second.find(v.col) == dis[u].second.end());
            if(dis[v.to].first > dis[u].first + cost) {
                dis[v.to].first = dis[u].first + cost;
                dis[v.to].second.clear();
                dis[v.to].second.insert(v.col);
                if(vis[v.to] == 0) {
                    vis[v.to] = 1;
                    Q.push(v.to);
                }
            }
            else if(dis[v.to].first == dis[u].first + cost && (dis[v.to].second.find(v.col) == dis[v.to].second.end())) {
                dis[v.to].second.insert(v.col);
                if(vis[v.to] == 0) {
                    vis[v.to] = 1;
                    Q.push(v.to);
                }
            }
        }

    }
}
int main() {
    while(~scanf("%d %d",&n,&m)) {
        for(int i = 0;i <= n;++i) G[i].clear();
        while(m--) {
            int x,y,z;scanf("%d %d %d",&x,&y,&z);
            G[x].push_back(Node{y,z});
            G[y].push_back(Node{x,z});
        }
        solve();
        printf("%d\n",dis[n].first == INF ? -1 : dis[n].first);
    }

   // system("pause");
    return 0;
}
View Code

Sequence:

这题真的想到了做法,但是一开始觉得不太可能这样做。(为什么不相信自己,去尝试一下呢。。

首先这里很明显是矩阵快速幂,但是这个向下取整的东西不好搞。

但是又可以想到,我们可以整除分块去求他。

然后就在整除分块里跑矩阵快速幂就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,set<int>> pii;
const int N = 1e6 + 5;
const int M = 1e5 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline int read(){
        int x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;

LL ADD(LL a,LL b) {return (a + b) % Mod;}
struct Mat{
    LL m[5][5];
    Mat operator * (Mat &a)const{
        Mat c;memset(c.m,0,sizeof(c.m));
        for(int i = 1;i <= 3;++i) {
            for(int j = 1;j <= 3;++j) {
                for(int k = 1;k <= 3;++k) {
                    c.m[i][j] = ADD(c.m[i][j],m[i][k] * a.m[k][j] % Mod);
                }
            }
        }
        return c;
    }
};

Mat quick_mi(Mat a,LL b) {
    Mat res;memset(res.m,0,sizeof(res.m));
    for(int i = 1;i <= 3;++i) res.m[i][i] = 1;
    while(b) {
        if(b & 1) res = res * a;
        a = a * a;
        b >>= 1;
    }
    return res;
}
LL f[5];
int main() {
    int ca;ca = read();
    while(ca--) {
        int A,B,C,D,P,n;
        A = read() % Mod,B = read() % Mod,C = read() % Mod,D = read() % Mod,P = read(),n = read();
        f[1] = A,f[2] = B;
        if(n == 1) printf("%lld\n",f[1]);
        else if(n == 2) printf("%lld\n",f[2]);
        else {
            LL tmp;
            for(int L = 3,r = 0;L <= n;L = r + 1) {
                if(P / L == 0) r = n;
                else r = min(n,P / (P / L));
               // printf("L is %d r is %d\n",L,r);
                int len = r - L + 1;
                LL k = P / L;
                Mat ans;memset(ans.m,0,sizeof(ans.m));
                if(len == 1) {
                    f[3] = D * f[2] % Mod + C * f[1] % Mod + k;
                    f[3] %= Mod;
                    f[1] = f[2];
                    f[2] = f[3];
                    tmp = f[3];
                }
                else if(len == 2) { 
                    f[3] = D * f[2] % Mod + C * f[1] % Mod + k;
                    f[3] %= Mod;
                    f[4] = D * f[3] % Mod + C * f[2] % Mod + k;
                    f[4] %= Mod;
                    f[2] = f[4],f[1] = f[3];
                    tmp = f[4];
                } 
                else {
                  //  printf("L is %d r is %d f[2] is %lld f[1] is %lld\n",L,r,f[2],f[1]);
                    f[3] = D * f[2] % Mod + C * f[1] % Mod + k;
                    f[3] %= Mod;
                    f[4] = D * f[3] % Mod + C * f[2] % Mod + k;
                    f[4] %= Mod;
                    Mat a;memset(a.m,0,sizeof(a.m));
                    a.m[1][1] = D,a.m[1][2] = C,a.m[1][3] = 1;
                    a.m[2][1] = 1,a.m[3][3] = 1;
                    ans.m[1][1] = f[4],ans.m[2][1] = f[3],ans.m[3][1] = k;
                    a = quick_mi(a,len - 2);
                    ans = a * ans;
                    f[2] = ans.m[1][1],f[1] = ans.m[2][1];
                    tmp = f[2];
                  //  printf("f[2] is %lld f[1] is %lld\n",f[2],f[1]);
                }
            }
            printf("%lld\n",tmp);
        }
    }


    system("pause");
    return 0;
}
/*
2 
1 2 3 4 10 10

*/
View Code

Swordsman:

牛马卡快读,普通快读都被卡掉了。。

我一开始的思路是,对k的全排列排序,然后不断维护每个排列的头,这样如果满足一个大那就肯定能在里面找到一个。

但是复杂度还是高了点,大概k! * N * k。

其实没必须对所有全排列排:考虑五个队列。

每个小顶堆维护一个k的最小。

我们从第一个开始,如果这个元素的第一值<=v,那么就说明他第一位置满足条件,那就放入第二位置。

以此类推,到最后一个堆还满足就可以杀掉了。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,int> pii;
const int N = 1e5 + 5;
const int M = 4e6 + 5;
const LL Mod = 199999;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
#define reads(n) FastIO::read(n)
namespace FastIO {
    const int SIZE = 1 << 16;
    char buf[SIZE], obuf[SIZE], str[60];
    int bi = SIZE, bn = SIZE, opt;
    int read(char *s) {
        while (bn) {
            for (; bi < bn && buf[bi] <= ' '; bi++);
            if (bi < bn) break;
            bn = fread(buf, 1, SIZE, stdin);
            bi = 0;
        }
        int sn = 0;
        while (bn) {
            for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi];
            if (bi < bn) break;
            bn = fread(buf, 1, SIZE, stdin);
            bi = 0;
        }
        s[sn] = 0;
        return sn;
    }
    bool read(int& x) {
        int n = read(str), bf;
        if (!n) return 0;
        int i = 0; if (str[i] == '-') bf = -1, i++; else bf = 1;
        for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
        if (bf < 0) x = -x;
        return 1;
    }
};

int v[5],f[5];
int len[121];
struct Node{
    int a[5],b[5];
}p[N];
bool vis[N];
struct cmp1 {
    bool operator() (const Node &a,const Node &b) {
        return a.a[0] > b.a[0];
    }
};
struct cmp2 {
    bool operator() (const Node &a,const Node &b) {
        return a.a[1] > b.a[1];
    }
};
struct cmp3 {
    bool operator() (const Node &a,const Node &b) {
        return a.a[2] > b.a[2];
    }
};
struct cmp4 {
    bool operator() (const Node &a,const Node &b) {
        return a.a[3] > b.a[3];
    }
};
struct cmp5 {
    bool operator() (const Node &a,const Node &b) {
        return a.a[4] > b.a[4];
    }
};
priority_queue<Node,vector<Node>,cmp1> Q1;
priority_queue<Node,vector<Node>,cmp2> Q2;
priority_queue<Node,vector<Node>,cmp3> Q3;
priority_queue<Node,vector<Node>,cmp4> Q4;
priority_queue<Node,vector<Node>,cmp5> Q5;
int main() {
    int ca;reads(ca);
    while(ca--) {
        int n,k;reads(n),reads(k);
        while(!Q1.empty()) Q1.pop();
        while(!Q2.empty()) Q2.pop();
        while(!Q3.empty()) Q3.pop();
        while(!Q4.empty()) Q4.pop();
        while(!Q5.empty()) Q5.pop();
        for(int i = 0;i < k;++i) reads(v[i]);
        for(int i = 1;i <= n;++i) {
            for(int j = 0;j < k;++j) reads(p[i].a[j]);
            for(int j = 0;j < k;++j) reads(p[i].b[j]);
            Q1.push(p[i]);
        }
        int kil = 0;
        while(1) {
            int f = 0;
            while(!Q1.empty()) {
                Node q = Q1.top();
                if(v[0] >= q.a[0]) {
                    if(k == 1) {
                        f = 1;
                        kil++;
                        for(int j = 0;j < k;++j) {
                            v[j] += q.b[j];
                        }
                    }
                    else Q2.push(q);
                    Q1.pop();
                } 
                else break;
            }
            while(!Q2.empty()) {
                Node q = Q2.top();
                if(v[1] >= q.a[1]) {
                    if(k == 2) {
                        f = 1;
                        kil++;
                        for(int j = 0;j < k;++j) {
                            v[j] += q.b[j];
                        }
                    }
                    else Q3.push(q);
                    Q2.pop();
                } 
                else break;
            }
            while(!Q3.empty()) {
                Node q = Q3.top();
                if(v[2] >= q.a[2]) {
                    if(k == 3) {
                        f = 1;
                        kil++;
                        for(int j = 0;j < k;++j) {
                            v[j] += q.b[j];
                        }
                    }
                    else Q4.push(q);
                    Q3.pop();
                } 
                else break;
            }
            while(!Q4.empty()) {
                Node q = Q4.top();
                if(v[3] >= q.a[3]) {
                    if(k == 4) {
                        f = 1;
                        kil++;
                        for(int j = 0;j < k;++j) {
                            v[j] += q.b[j];
                        }
                    }
                    else Q5.push(q);
                    Q4.pop();
                } 
                else break;
            }
            while(!Q5.empty()) {
                Node q = Q5.top();
                if(v[4] >= q.a[4]) {
                    f = 1;
                    kil++;
                    for(int j = 0;j < k;++j) {
                        v[j] += q.b[j];
                    }
                    Q5.pop();
                } 
                else break;
            }
            if(f == 0) break;
        }
        printf("%d\n",kil);
        for(int i = 0;i < k;++i) printf("%d%c",v[i],i == k - 1 ? '\n' : ' ');
    }

    system("pause");
    return 0;
}
View Code

 

posted @ 2021-06-02 21:46  levill  阅读(40)  评论(0编辑  收藏  举报