《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; }
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 */
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; }