2019南京网络赛
A The beautiful values of the palace
知识点:模拟,树状数组+离散+二维前缀和
- 根据坐标算值(先把中心当作1,然后用n*n减去,反过来算更容易)
- 将特殊点加入队列
- 读入询问,对于询问 ,如果 为二维前缀和,那么答案就是
- 将所有询问需要求得的二维前缀的坐标也加入队列,按照x为第一参考进行排序,对y离散化
- 排序之后从小到大依次考虑,即x是从小到大考虑的,每次遇到新的特殊点就插入到树状数组中,遇到查询 就在树状数组中查询(1,y-1)的和即可。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1000010; int T; int n,m,p; ll d[N],c[N]; struct node{ int x1,y1,x2,y2; }; vector<node> qu;//查询 struct Node{ int x,y; int type;//type为0表示添加新点 }a[N]; bool cmp(Node a,Node b){ if(a.x == b.x){ if(a.y == b.y)return a.type == 0; return a.y < b.y; } return a.x < b.x; } vector<int> v;//离散y void add(int x,int y){ for(;x<N;x+=x&-x)c[x] += y; } ll ask(int x){ ll res = 0; for(;x;x-=x&-x)res += c[x]; return res; } map<int,map<int,int>> mp; int id[N]; ll get(int x,int y){ int cx = n / 2 + 1; int cy = n / 2 + 1;//(cx,cy)即中心坐标 int k = max(abs(x-cx),abs(y-cy));//k表示在第几圈 if(k == 0)return 1ll * n * n; //printf("\n(%d,%d) k : %d\n",x,y,k); ll res = d[k-1];//圈内有多少个 //分4个case计算 if(y-cy == k && x < cx + k){//在上层 res += cx + k - x; }else if(cx - x == k && y < cy + k){//在左侧 res += k * 2 + cy + k - y; }else if(cy - y == k && x > cx - k){//在下层 res += k * 4 + x - (cx - k); }else if(x - cx == k){//在右侧 res += k * 6 + y - (cy - k); } res = 1ll * n * n - res;//最后倒过来,因为上面是按照中心为1算的 return res + 1; } int calc(ll x){ int res= 0; while(x){res += x % 10;x /= 10;} return res; } int main(){ scanf("%d",&T); d[0] = 1;d[1] = 8; for(int i=2;i<N;i++)d[i] = d[i-1] + 8; for(int i=1;i<N;i++)d[i] += d[i-1];//计算i圈以内有多少个点 while(T--){ mp.clear();v.clear();qu.clear(); memset(c,0,sizeof c); scanf("%d%d%d",&n,&m,&p); for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); a[i] = {x,y,0}; } for(int i=1;i<=p;i++){ int x1,x2,y1,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); qu.push_back({x1,y1,x2,y2}); a[++m] = {x1-1,y1-1,1}; a[++m] = {x2,y2,1}; a[++m] = {x1-1,y2,1}; a[++m] = {x2,y1-1,1}; } for(int i=1;i<=m;i++){ v.push_back(a[i].y); } sort(v.begin(),v.end()); v.erase(unique(v.begin(),v.end()),v.end()); sort(a+1,a+m+1,cmp); for(int i=1;i<=m;i++){ id[i] = lower_bound(v.begin(),v.end(),a[i].y) - v.begin() + 1; } for(int i=1;i<=m;i++){ if(a[i].type == 0)add(id[i],calc(get(a[i].x,a[i].y))); else if(a[i].type == 1)mp[a[i].x][a[i].y] = ask(id[i]); } for(int i=0;i<p;i++){ int x1 = qu[i].x1,x2 = qu[i].x2,y1 = qu[i].y1,y2 = qu[i].y2; ll res = mp[x2][y2] + mp[x1-1][y1-1] - mp[x1-1][y2] - mp[x2][y1-1]; printf("%lld\n",res); } } return 0; }
D Robots
设 为 u 到 n 的期望天数,那么有:
设 为 u 到 n 的期望消耗,那么有:
因为你在 u 这个点过去的这一天,会对之后的每一天的贡献都额外增加 1,所以要加 d[u] 和
#include <bits/stdc++.h> using namespace std; const int N = 1e6+10; int head[N],ver[N],nxt[N],tot,deg[N],sz[N]; int T,n,m; void add(int x,int y){ ver[++tot] = y;nxt[tot] = head[x];head[x] = tot; } double f[N],d[N]; int main(){ scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); tot = 0; for(int i=1;i<=n;i++){ head[i] = 0;f[i] = d[i] = 0;deg[i] = 0;sz[i] = 0; } for(int i=1;i<=m;i++){ int x,y;scanf("%d%d",&x,&y); add(y,x); deg[x]++;sz[x]++; } queue<int> q; q.push(n); while(q.size()){ int x = q.front();q.pop(); for(int i=head[x];i;i=nxt[i]){ int y = ver[i]; f[y] += f[x]; d[y] += d[x]; if(-- deg[y] == 0){ //if刚进来时,f[y] 和 d[y] 为 累加和 f[y] = ((d[y]+sz[y]+1)/sz[y]+f[y]+d[y]+sz[y]+1)/sz[y]; d[y] = (d[y] + sz[y] + 1)/sz[y]; q.push(y); } } } printf("%.2f\n",f[1]); } return 0; }
F Greedy Sequence
权值线段树维护出现过的数的最大值,即[l,r]
表示当前所有数中,值在范围的数的最大值为多少
滑动区间维护线段树,每次查询[1,x-1]
中出现的最大数,如果没有答案为0
最后记忆化搜索即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; int T; const int N = 100010; int a[N],n,k,b[N],d[N]; struct Seg{ int l,r; int mx; }t[4*N]; void build(int p,int l,int r){ t[p].l = l;t[p].r = r; if(l == r){ t[p].mx = 0;return; } int mid = l + r >> 1; build(p*2,l,mid); build(p*2+1,mid+1,r); t[p].mx = 0; } void upd(int p,int x,int add){ if(t[p].l == t[p].r && t[p].l == x){ t[p].mx = add == 1 ? x : 0; return; } int mid = t[p].l + t[p].r >> 1; if(mid >= x)upd(p*2,x,add); if(mid < x)upd(p*2+1,x,add); t[p].mx = max(t[p*2].mx,t[p*2+1].mx); } int query(int p,int l,int r){ if(t[p].l >= l && t[p].r <= r){ return t[p].mx; } int mid = t[p].l + t[p].r >> 1; int res = 0; if(mid >= l)res = max(res,query(p*2,l,r)); if(mid < r)res = max(res,query(p*2+1,l,r)); return res; } ll get(int x){ if(b[x] == 0)return d[x] = 1; if(d[x])return d[x]; d[x] = get(b[x]) + 1; return d[x]; } int main(){ scanf("%d",&T); while(T--){ scanf("%d%d",&n,&k); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++)d[i] = 0; int l = 1,r=min(1+k,n); build(1,1,n); for(int i=l;i<=r;i++){ upd(1,a[i],1); } for(int i=1;i<=n;i++){ b[a[i]] = query(1,1,a[i]-1); if(i-l>=k){ upd(1,a[l],0); l++; } if(r<n){ upd(1,a[++r],1); } } ll res = 0; for(int i=1;i<=n;i++)res += get(a[i]); for(int i=1;i<=n;i++){ if(i>1)printf(" "); printf("%d",get(i)); } puts(""); } return 0; }
H. Holy Grail
每次跑最短路即可,返回答案为正则添加负权边,否则添加正边(注意不能用迪杰斯特拉)
#include <bits/stdc++.h> using namespace std; const int N = 1010; typedef long long ll; const ll INF = 1e18; int head[N],ver[N],Nxt[N],tot; int v[N],n,m; ll edge[N],d[N]; void add(int x,int y,ll z){ ver[++tot] = y;edge[tot] = z;Nxt[tot] = head[x];head[x] = tot; } ll dij(int s,int t){ queue<int> q; for(int i = 0; i <= n + 5; i++){ d[i] = INF;v[i] = 0; } d[s] = 0; q.push(s); v[s] = 1; while(q.size()) { int x = q.front(); q.pop(); v[x] = 0; for(int i = head[x]; i; i = Nxt[i]){ int y = ver[i]; if(d[y] > d[x] + edge[i]) { d[y] = d[x] + edge[i]; if(v[y] == 0){ v[y] = 1; q.push(y); } } } } return d[t]; } int main(){ int T;scanf("%d",&T); for(int o=0;o<T;o++){ scanf("%d%d",&n,&m); tot = 0; for(int i=1;i<=n;i++)head[i] = 0; for(int i=1;i<=m;i++){ int x,y; ll z; scanf("%d%d%lld",&x,&y,&z); x++;y++; add(x,y,z); } for(int j=1;j<=6;j++){ int s,t; scanf("%d%d",&s,&t); s++;t++; ll dis = dij(t,s); printf("%lld\n",-dis); add(s,t,-dis); } } return 0; }
注:转载请注明出处
本文作者:kpole
本文链接:https://www.cnblogs.com/1625--H/p/11443960.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步