CoderForces Round54 (A~E)
題解:這一題讀完題就寫了吧。就是讓你刪除一個字母,使得剩下的字符組成的字符串的字典序最小;我們只要第一個當前位置的字符比下一個字符小的位置把該字符刪去即可;
參考代碼:
#include<bits/stdc++.h> using namespace std; #define PI acos(-1.0) #define RI register int #define clr(a,b) memset(a,b,sizeof a) typedef long long ll; const int INF=0x3f3f3f3f; const int maxn=2e5+10; int n; char str[maxn]; int main() { scanf("%d",&n); scanf("%s",str); int len=strlen(str),temp=len-1; for(int i=0;i<len-1;++i) { if(str[i]-str[i+1]>0) { temp=i; break; } } for(int i=0;i<len;++i) if(i!=temp) printf("%c",str[i]); printf("\n"); return 0; }
ProblemB Divisor Subtraction
題目鏈接 題解:這一題就是讓你找一個數的最小質因數,並減去它,一直循環,直到該數為零;考慮輸入的數num,如果num為偶數,那麽次數即為num/2(因為每次都是2);對於一個奇數,它的第一個最小質因數一定是奇數,則經過一次循環後,num會變為偶數,回到了前面的情況;因此,只要分兩種情況即可; 參考代碼:#include <bits/stdc++.h> using namespace std; typedef long long ll; ll N; int main() { cin>>N; for(ll i=2;i*i<=N;++i) if(N%i==0) { printf("%lld\n",(N-i)/2+1);return 0; } puts("1"); return 0; }
Problem C Meme Problem
題目鏈接 題解:這一題數學公式推一下就行了Orz; 參考代碼:#include<bits/stdc++.h> using namespace std; typedef long long ll; #define clr(a,b) memset(a,b,sizeof a) int main() { double a,b,d; int t; scanf("%d",&t); while(t--) { scanf("%lf",&d); double k=d*d-4*d; if(0<d&&d<4) puts("N"); else { a=(d+sqrt(k))/2; b=(d-sqrt(k))/2; printf("Y %.9f %.9f\n",a,b); } } return 0; }
Problem D. Edge Deletion
題目鏈接 題解:給定 N 個點 M 條邊的無向簡單聯通圖,留下最多 K 條邊,求剩下的點裏面從 1 號頂點到其余各點最短路大小等於原先最短路大小的點最多怎麽構造。這題用到貪心思想,我們可以在第一次跑 dij 時直接采用貪心策略,即:若當前答案集合的大小小於 K 且優先隊列非空,則繼續優先隊列BFS,每次把一條邊加入到答案集合中。因為是在求解最短路過程中向答案集合中加邊,可知這就是一種最優策略。 參考代碼:#include<bits/stdc++.h> using namespace std; typedef long long LL; const int Maxn=3e5+10; const LL INF=1e15; int n,m,k,a[Maxn],f[Maxn],fa[Maxn]; LL d[Maxn]; bool boo[Maxn]; struct qnode{ int v; LL cost; bool operator < (const qnode &r) const {return cost>r.cost;} }; struct node{ int v; LL cost; int w; }; vector<node> e[Maxn]; set<int> s; set<int>::iterator it; void dijkstra() { for (int i=1; i<=n; i++) boo[i]=false,d[i]=INF; priority_queue<qnode> q; while(!q.empty()) q.pop(); d[1]=0; q.push(qnode{1,0}); while (!q.empty()) { qnode temp=q.top();q.pop(); int u=temp.v; if (boo[u]) continue; boo[u]=true; for (int i=0,len=e[u].size();i<len;i++) { int v=e[u][i].v; LL cost=e[u][i].cost; if(!boo[v] && d[v]>d[u]+cost) { d[v]=d[u]+cost; q.push(qnode{v,d[v]}); f[v]=e[u][i].w; fa[v]=u; } } } } int main() { while(scanf("%d%d%d",&n,&m,&k)!=EOF) { for(int i=1; i<=n; i++) e[i].clear(); for(int i=1; i<=m; i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); e[x].push_back(node{y,z,i}); e[y].push_back(node{x,z,i}); } dijkstra(); if(k>=n-1) { printf("%d\n",n-1); for(int i=2; i<=n; i++) if (i!=n) printf("%d ",f[i]); else printf("%d\n",f[i]); } else { s.clear(); for(int i=1; i<=n; i++) d[i]=0; for(int i=2; i<=n; i++) d[fa[i]]++,s.insert(f[i]); a[0]=0; for(int i=1; i<=n; i++) if(d[i]==0) a[++a[0]]=i; int x=n-1; while(x>k) { int u=a[a[0]]; a[0]--; s.erase(f[u]); d[fa[u]]--; if(d[fa[u]]==0) a[++a[0]]=fa[u]; x--; } printf("%d\n",x); int i=0; for(it=s.begin();it!=s.end();it++) { i++; printf("%d",(*it)); if(i==x) printf("\n"); else printf(" "); } } } return 0; }
Problem E. Vasya and a Tree
題目鏈接 題解:題意:
給你一棵n個節點的樹,每個點有一個權值,初始全為0,m次操作,每次三個數(v, d, x)表示只考慮以v為根的子樹,將所有與v點距離小於等於d的點權值全部加上x,求所有操作完畢後,所有節點的值
首先要明確兩件事情
性質1.每個人的操作只會影響到他的子孫(包括自己) 性質1.每個人的操作只會影響到他的子孫(包括自己)性質1.每個人的操作只會影響到他的子孫(包括自己)
性質2.每個人只會被他祖先的操作所影響(包括自己) 性質2.每個人只會被他祖先的操作所影響(包括自己)性質2.每個人只會被他祖先的操作所影響(包括自己)
也就是說,如果我們能在訪問到某個節點時,統計出所有影響到該節點的祖先操作 也就是說,如果我們能在訪問到某個節點時,統計出所有影響到該節點的祖先操作也就是說,如果我們能在訪問到某個節點時,統計出所有影響到該節點的祖先操作
就可以統計出這個節點的最終權值 就可以統計出這個節點的最終權值就可以統計出這個節點的最終權值
而對於每個操作,我們只要用一個dep數組保存每個深度被增加的值 而對於每個操作,我們只要用一個dep數組保存每個深度被增加的值而對於每個操作,我們只要用一個dep數組保存每個深度被增加的值;
所有深度大於當前節點的操作都會影響到當前節點,如果用線段樹就是一個區間求和問題 所有深度大於當前節點的操作都會影響到當前節點,如果用線段樹就是一個區間求和問題所有深度大於當前節點的操作都會影響到當前節點,如果用線段樹就是一個區間求和問題
為了減少代碼量我們用樹狀數組,更新時只在本次操作的最深的深度更新 為了減少代碼量我們用樹狀數組,更新時只在本次操作的最深的深度更新為了減少代碼量我們用樹狀數組,更新時只在本次操作的最深的深度更新;
這樣求一個1~maxdep的前綴和就是所有更新了根節點的操作 這樣求一個1~maxdep的前綴和就是所有更新了根節點的操作這樣求一個1~maxdep的前綴和就是所有更新了根節點的操作;
在求一個1~(nowdep-1)的前綴和就是所有不包含當前節點的操作 在求一個1~(nowdep-1)的前綴和就是所有不包含當前節點的操作在求一個1~(nowdep-1)的前綴和就是所有不包含當前節點的操作;兩個前綴和相減就是當前節點被更新的值 兩個前綴和相減就是當前節點被更新的值兩個前綴和相減就是當前節點被更新的值;為了保證每個操作只影響自己子樹內的節點,在dfs退出子樹時 為了保證每個操作只影響自己子樹內的節點,在dfs退出子樹時為了保證每個操作只影響自己子樹內的節點,在dfs退出子樹時,要將當前根節點的所有修改值還原 要將當前根節點的所有修改值還原要將當前根節點的所有修改值還原。
參考代碼:
#include<bits/stdc++.h> using namespace std; #define clr(a,b) memset(a,b,sizeof a) #define PI acos(-1.0) #define lowbit(x) x&-x typedef long long ll; const int INF=0x3f3f3f3f; const int maxn=3e5+10; vector<int> G[maxn],dep[maxn],val[maxn]; int n,m,v,d,x,y; ll tree[maxn],ans[maxn]; inline void readint(int &k) { int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘) {if(ch==‘-‘) f=-1; ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘) {x=x*10+ch-‘0‘;ch=getchar();} k=x*f; } inline void add(int x,int val) { while(x<=n) { tree[x]+=val; x+=lowbit(x); } } inline ll sum(int x) { ll ans=0; while(x) { ans+=tree[x]; x-=lowbit(x); } return ans; } inline void dfs(int t,int fa,int depth) { for(int i=0;i<dep[t].size();++i) add(min(dep[t][i]+depth,n),val[t][i]); ans[t]=sum(n)-sum(depth-1); for(int i=0;i<G[t].size();++i) { if(G[t][i]==fa) continue; dfs(G[t][i],t,depth+1); } for(int i=0;i<dep[t].size();++i) add(min(dep[t][i]+depth,n),-val[t][i]); } int main() { clr(tree,0);clr(ans,0); readint(n); for(int i=1;i<=n-1;++i) { readint(x),readint(y); G[x].push_back(y);G[y].push_back(x); } readint(m); for(int i=1;i<=m;++i) { readint(v),readint(d),readint(x); dep[v].push_back(d); val[v].push_back(x); } dfs(1,0,1); for(int i=1;i<=n;++i) printf("%lld%c",ans[i],i==n?‘\n‘:‘ ‘); return 0; }
CoderForces Round54 (A~E)