The Preliminary Contest for ICPC Asia Nanjing 2019
A The beautiful values of the palace
题目链接
题意:在一个n*n的螺旋矩阵,给你m个坐标(x,y)代表此下标是存在数的。再给q个询问,询问左下角(x1,y1)和右上角(x2,y2)为矩阵中存在的数的数位和。
思路:对于一个坐标(x,y)在螺旋矩阵中的数值,可以通过近似O(1)的计算得出。计算矩阵中有多少个存在的值,我们通过对于m个坐标进行排序,建立主席树。x坐标存在重复所以需要lower_bound(),upper_bound()二分。
#include <bits/stdc++.h> #define maxn 100005 #define inf 0x3f3f3f3f typedef long long ll; using namespace std; struct node{ int l,r; ll cnt; node(){ l=r=cnt=0; } }T[maxn*22]; struct point{ int x,y; }p[maxn]; bool cmp(point a,point b){ if(a.x==b.x) return a.y<b.y; return a.x<b.x; } int get_beauty(ll n, ll x, ll y){ ll top = n - y, bottom = y - 1, lft = x - 1, rht = n - x; ll dis = min(min(top,bottom),min(lft,rht)); ll has = n * n - ((n - dis * 2) * (n - dis * 2)); ll edge = n - 2 * dis - 1; if(x == n - dis){ has += top - dis + 1; } else if(y == dis + 1){ has += edge + rht - dis + 1; } else if(x == dis + 1){ has += 2 * edge + bottom - dis + 1; } else{ has += 3 * edge + lft - dis + 1; } int wei = 0; while(has){ wei += has % 10; has /= 10; } return wei; } int rt[maxn]; int xCopy[maxn]; int tot=0; int n,m,q; void update(int &x,int y,int l,int r,int pos,int val){ T[++tot]=T[y]; T[tot].cnt+=val; x=tot; if(l==r)return; int mid=(l+r)>>1; if(pos<=mid) update(T[x].l,T[y].l,l,mid,pos,val); else update(T[x].r,T[y].r,mid+1,r,pos,val); } int ans=0; void query(int x,int y,int l,int r,int L,int R){ if (L <= l && r <= R) { ans += T[y].cnt - T[x].cnt; return; } int mid = l + r >> 1; if (L <= mid)query(T[x].l, T[y].l, l, mid, L, R); if (R > mid)query(T[x].r, T[y].r, mid + 1, r, L, R); } void init(){ tot=0; } void input(){ scanf("%d%d%d",&n,&m,&q); int i; for(i=1;i<=m;i++) scanf("%d%d",&p[i].x,&p[i].y); sort(p+1,p+1+m,cmp); for(i=1;i<=m;i++){ update(rt[i],rt[i-1],1,n,p[i].y,get_beauty(1ll*n,1ll*p[i].x,1ll*p[i].y)); xCopy[i]=p[i].x; } int x1,y1,x2,y2; for(i=1;i<=q;i++){ scanf("%d%d%d%d",&x1,&y1,&x2,&y2); int pos1=lower_bound(xCopy+1,xCopy+1+m,x1)-xCopy; int pos2=upper_bound(xCopy+1,xCopy+1+m,x2)-xCopy-1; // cout<<pos1<<' '<<pos2<<endl; ans=0; query(rt[pos1-1],rt[pos2],1,n,y1,y2); printf("%d\n",ans); } } int main(){ int t; scanf("%d",&t); while(t--){ init(); input(); // solve(); } }
D Robots
题目链接
题意:问一个机器人从图中1到n所需要的燃油值期望为多少?每次耗费的燃油值,是当前已经历的天数值。
思路:拓扑求出天数的期望值,再拓扑求出耗油的期望值。
其中t[u]是天数期望,f[u]是耗油期望
#include <bits/stdc++.h> #define maxn 100005 using namespace std; int t; int n,m; vector <int>G[maxn]; vector <int>g[maxn]; int indeg[maxn]; int indegCopy[maxn]; double day[maxn]; double ans[maxn]; void topo(){ int i; queue <int>q; for(i=1;i<=n;i++) if(!indeg[i]){ day[i]=0; q.push(i); } while(!q.empty()){ int f=q.front(); q.pop(); for(int i=0;i<G[f].size();i++){ indeg[G[f][i]]--; if(!indeg[G[f][i]]) { q.push(G[f][i]); for(int j=0;j<g[G[f][i]].size();j++) day[G[f][i]]+=day[g[G[f][i]][j]]; day[G[f][i]]+=(g[G[f][i]].size()+1); day[G[f][i]]/=g[G[f][i]].size(); } } } } void topo2(){ int i; queue <int>q; for(i=1;i<=n;i++) if(!indeg[i]){ ans[i]=0; q.push(i); } while(!q.empty()){ int f=q.front(); q.pop(); for(int i=0;i<G[f].size();i++){ indeg[G[f][i]]--; if(!indeg[G[f][i]]) { q.push(G[f][i]); for(int j=0;j<g[G[f][i]].size();j++) ans[G[f][i]]+=ans[g[G[f][i]][j]]; ans[G[f][i]]+=(g[G[f][i]].size()+1)*day[G[f][i]]; ans[G[f][i]]/=g[G[f][i]].size(); } } } } void input(){ scanf("%d%d",&n,&m); int i,u,v; for(i=1;i<=n;i++){ G[i].clear(); g[i].clear(); } memset(day,0,sizeof day); memset(ans,0,sizeof ans); memset(indeg,0,sizeof indeg); memset(indegCopy,0,sizeof indegCopy); for(i=1;i<=m;i++){ scanf("%d%d",&u,&v); G[v].push_back(u); g[u].push_back(v); indeg[u]++; indegCopy[u]++; } } void solve(){ topo(); // for(int i=1;i<=n;i++) // cout<<day[i]<<endl; for(int i=1;i<=n;i++) indeg[i]=indegCopy[i]; topo2(); printf("%.2lf\n",ans[1]); } int main(){ scanf("%d",&t); while(t--){ input(); solve(); } }
F Greedy Sequence
题目链接
题意:有n个序列S1、S2....Sn ,每个序列定义:1、Si[1]=i。2、每个序列Si都是非递增序列 3、序列Si中的上一个值和下一个值在给定排列a中的距离差需要小于等于k。4、满足Si字典序大于Si-1 5、未确定的值用0代替。
要求寻找每个序列中非零值个数。
思路:滑动窗口+multiset二分获得元素的下一个元素,记忆化O(n)记录答案
#include <bits/stdc++.h> #define maxn 100005 #define inf 0x3f3f3f3f using namespace std; int n,k; int a[maxn]; int dis[maxn]; int ans[maxn]; multiset <int>st; multiset <int>::iterator it; void init(){ st.clear(); int i; for(i=1;i<=k;i++) st.insert(a[i]); for(i=1;i<=n;i++){ st.erase(a[i]); if(i>1) st.insert(a[i-1]); if(i>k+1) st.erase(a[i-k-1]); if(i+k<=n) st.insert(a[i+k]); it=st.lower_bound(a[i]); if(it!=st.begin()) { it--; dis[a[i]]=*it; }else dis[a[i]]=0; } } void input(){ scanf("%d%d",&n,&k); int i; for(i=1;i<=n;i++) scanf("%d",&a[i]); init(); // for(i=1;i<=n;i++){ // cout<<a[i]<<" "<<dis[a[i]]<<endl; // } for(i=1;i<=n;i++){ if(dis[i]!=0) ans[i]=ans[dis[i]]+1; else ans[i]=1; } for(i=1;i<=n;i++) printf("%d%c",ans[i],i==n?'\n':' '); } int main(){ int t; scanf("%d",&t); while(t--){ input(); // solve(); } }
H Holy Grail
题目链接
题意:n个点m条边,存在负边但不存在负环的图。给出6个查询,询问点u和v,求v到u增加边(可以为负),使权值最小。
思路:输出v到u的最短路的相反数,并将u到v,权值为刚才求出的答案这条边加入到图中
#include <bits/stdc++.h> #define maxn 305 #define inf 0x3f3f3f3f using namespace std; int n,m; struct edge{ int to,cost; }; typedef pair<int,int>P; vector <edge> G[maxn]; int dis[maxn]; void dij(int a) { priority_queue<P,vector<P>,greater<P> >q; memset(dis,0x3f,sizeof(dis)); dis[a]=0; q.push(P(0,a)); while(!q.empty()) { P temp=q.top(); q.pop(); int v=temp.second; if(dis[v]<temp.first)continue; for(int i=0;i<G[v].size();i++) { edge e=G[v][i]; if(dis[e.to]>dis[v]+e.cost) { dis[e.to]=dis[v]+e.cost; q.push(P(dis[e.to],e.to)); } } } } void input(){ scanf("%d%d",&n,&m); int i; for(i=0;i<n;i++) G[i].clear(); int u,v,w; for(i=0;i<m;i++){ scanf("%d%d%d",&u,&v,&w); G[u].push_back((edge){v,w}); } int s,t; int q=6; while(q--){ scanf("%d%d",&s,&t); dij(t); printf("%d\n",-dis[s]); G[s].push_back((edge){t,-dis[s]}); } } int main(){ int t; scanf("%d",&t); while(t--){ input(); // solve(); } }