-
PJ
-
T1
首先容易发现每次都会取走 \(\dfrac{n-1}{3}+1\) 个苹果,因此 \(\lceil \dfrac{n}{\dfrac{n-1}{3}+1} \rceil\) 即为总天数。
然后我们可以注意到当第一次出现 \(n-1 \bmod 3=0\) 时第 \(n\) 个苹果会被取到,因此我们在不断取苹果的过程中判断并记录即可。
int n,d=1,dd; cin>>n; while(n>0){ if((n-1)%3==0&&!dd) dd=d; n=n-((n-1)/3+1); d++; } cout<<d-1<<' '<<dd;
-
T2
考虑到每个站点都要从它前面最小的站点转移而来,于是用 \(mnv\) 与 \(now[]\) 分别记录 前缀最小价格 与 在最小价格所在站点时车剩余的油量,然后按题意模拟即可。
#define dd double int n,d,pre=1,mnv=1e9; int ans[100031]; dd now[100031]; int v[100031],sum[100031]; int a[100031]; cin>>n>>d; for(int i=1;i<n;i++) cin>>v[i],sum[i+1]=sum[i]+v[i]; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=2;i<=n;i++){ if(a[i-1]<mnv) pre=i-1,mnv=a[i-1]; ans[i]+=ans[pre]; dd oil=(dd)(sum[i]-sum[pre])/(dd)(d); if(now[pre]>oil) now[pre]-=oil; else{ ans[i]+=ceil(oil-now[pre])*a[pre]; now[i]=ceil(oil-now[pre])-oil; } now[i]+=now[pre]; } cout<<ans[n];
-
T3
将 \(\sqrt{\Delta}\) 转化为 \(c \sqrt{d}\) 的形式,根据 \(\sqrt{d}\) 是否为有理数进行讨论:
-
若其为有理数(\(d=0\) 或 \(d=1\)),约分后输出 \(\dfrac{-b+ad}{2a}\)。
-
否则,将其分解为 \(\dfrac{-b}{2a} + \dfrac{cd}{2a}\) 的形式,约分后输出即可(后者仅需将 \(c\) 与 \(2a\) 约分)。
int t,m; cin>>t>>m; void solve(){ int a,b,c; cin>>a>>b>>c; if(a<0) a=-a,b=-b,c=-c; int d=b*b-4*a*c,k=1; if(d<0) cout<<"NO"; else{ for(int i=2;i*i<=d;i++) while(d%(i*i)==0) k*=i,d/=(i*i); if(d==0||d==1){ int t=(__gcd(2*a,-b+k*d)); cout<<(-b+k*d)/t; if(2*a/t!=1) cout<<"/"<<2*a/t; } else{ int t=(__gcd(2*a,-b)); if((-b)/t!=0){ cout<<(-b)/t; if(2*a/t!=1) cout<<"/"<<2*a/t; cout<<"+"; } t=(__gcd(2*a,k)); if(k/t!=1) cout<<k/t<<"*"; cout<<"sqrt("<<d<<")"; if(2*a/t!=1) cout<<"/"<<2*a/t; } } cout<<"\n"; }
-
T4
我们考虑 \(dp\) 的思想,令 \(dis_{i,j}\) 表示在节点 \(i\) 时刻 \(j\)(模 \(k\) 意义下),然后对图进行一遍 \(dijkstra\) 即可。
答案为 \(dis_{n,0}\)。
#include<bits/stdc++.h> using namespace std; int n,m,k; struct NodeMessage{ int u,p,d; bool operator < (const NodeMessage &x) const { return d>x.d; } }; int dis[200031][131]; bool vis[200031][131]; vector<pair<int,int> > G[200031]; priority_queue<NodeMessage> q; signed main(){ cin>>n>>m>>k; for(int i=1,u,v,w;i<=m;i++){ cin>>u>>v>>w; G[u].push_back({v,w}); } memset(dis,0x3f,sizeof(dis)); q.push({1,0,dis[1][0]=0}); while(!q.empty()){ int nu=q.top().u,np=q.top().p; q.pop(); if(vis[nu][np]) continue; vis[nu][np]=1; for(auto i:G[nu]){ int nv=i.first,nw=i.second; int dd=dis[nu][np],pp=(np+1)%k; if(dd<nw) dd+=ceil((double)(nw-dd)/(double)(k))*k; if(dis[nv][pp]>dd+1) q.push({nv,pp,dis[nv][pp]=dd+1}); } } cout<<(dis[n][0]==0x3f3f3f3f?-1:dis[n][0]); return 0; }
-
-
TG
-
T1
枚举所有状态
check
即可。#include<bits/stdc++.h> using namespace std; int n,ans; int r[31][5]; bool check(int a,int b,int c,int d,int e){ int s[5]; s[0]=a,s[1]=b,s[2]=c,s[3]=d,s[4]=e; for(int i=1;i<=n;i++){ int ss=0; for(int j=0;j<5;j++) if(r[i][j]!=s[j]) ss++; if(ss>2||ss==0) return 0; else if(ss==2){ int p1=-1,p2=-1; for(int j=0;j<5;j++){ if(r[i][j]!=s[j]&&p1==-1) p1=j; else if(r[i][j]!=s[j]&&p1!=-1){ p2=j; break; } } if(abs(p1-p2)!=1) return 0; int x=(s[p1]-r[i][p1]>=0?s[p1]-r[i][p1]:s[p1]+10-r[i][p1]); int y=(s[p2]-r[i][p2]>=0?s[p2]-r[i][p2]:s[p2]+10-r[i][p2]); if(x!=y) return 0; } } return 1; } int main(){ cin>>n; for(int i=1;i<=n;i++) for(int j=0;j<5;j++) cin>>r[i][j]; for(int a=0;a<=9;a++) for(int b=0;b<=9;b++) for(int c=0;c<=9;c++) for(int d=0;d<=9;d++) for(int e=0;e<=9;e++) if(check(a,b,c,d,e)) ans++; cout<<ans; return 0; }
-
T2
考虑一种 \(O(n^2)\) 的做法:拿一个栈,不断往后扩展,遇到和栈顶相同就弹栈,统计数量即可。
于是正解就是将所有栈的状态表示成一个
hash
值,扔到map
里看有几个和它相同的即可累加。#include<bits/stdc++.h> #define int long long #define ull unsigned long long using namespace std; int n,ans,hsh; map<int,int> cnt; stack<int> s; ull p[2000031]; string t; signed main(){ cin>>n>>t; p[0]=1; for(int i=1;i<=2000010;i++) p[i]=p[i-1]*13331; cnt[0]++; for(int i=0;i<n;i++){ if(!s.empty()&&s.top()==t[i]) hsh-=s.top()*p[s.size()],s.pop(); else s.push(t[i]),hsh+=s.top()*p[s.size()]; ans+=cnt[hsh],cnt[hsh]++; } cout<<ans; return 0; }
-
T3
大模拟。实在不想讲了。放个tj链接罢。
#include<bits/stdc++.h> #define int long long #define pii pair<int,int> using namespace std; int n; const int MAXN=331; string New_Type_Meb_Type[MAXN],New_Type_Meb_Name[MAXN]; struct Type{ string Name; int M_Size,M_Align; vector<Type*> M_Type; vector<string> M_Name; void cls(){ Name.clear(),M_Size=M_Align=0; M_Type.clear(),M_Name.clear(); } }; Type Def_Type[MAXN]; int Type_Num; map<string,Type*> Name_to_Type; struct Elem{ Type Elem_Type; string Name; int Addr; void cls(){ Elem_Type.cls(); Name.clear(),Addr=0; } }; Elem Def_Elem[MAXN]; int Elem_Num; map<string,Elem*> Name_to_Elem; int Addr_Pos; map<pii,Elem*> Addr_to_Elem; void Init(){ Def_Type[++Type_Num].Name="byte"; Def_Type[Type_Num].M_Size=Def_Type[Type_Num].M_Align=1; Name_to_Type["byte"]=&Def_Type[Type_Num]; Def_Type[++Type_Num].Name="short"; Def_Type[Type_Num].M_Size=Def_Type[Type_Num].M_Align=2; Name_to_Type["short"]=&Def_Type[Type_Num]; Def_Type[++Type_Num].Name="int"; Def_Type[Type_Num].M_Size=Def_Type[Type_Num].M_Align=4; Name_to_Type["int"]=&Def_Type[Type_Num]; Def_Type[++Type_Num].Name="long"; Def_Type[Type_Num].M_Size=Def_Type[Type_Num].M_Align=8; Name_to_Type["long"]=&Def_Type[Type_Num]; } void Create_New_Type(string N_Type_Name,int N_Type_Num,string *N_Type_Meb_Type,string *N_Type_Meb_Name){ Type New_Type; New_Type.cls(); New_Type.Name=N_Type_Name; for(int i=1;i<=N_Type_Num;i++){ New_Type.M_Type.push_back(Name_to_Type[N_Type_Meb_Type[i]]); New_Type.M_Name.push_back(N_Type_Meb_Name[i]); } int N_Pos=0; vector<Type*>::iterator N_It=New_Type.M_Type.begin(); for(;N_It!=New_Type.M_Type.end();N_It++){ int T_Size=(*N_It)->M_Size,T_Align=(*N_It)->M_Align; New_Type.M_Align=max(New_Type.M_Align,T_Align); if(N_Pos%T_Align) N_Pos=(N_Pos/T_Align+1)*T_Align; N_Pos+=T_Size; } if(N_Pos%New_Type.M_Align) N_Pos=(N_Pos/New_Type.M_Align+1)*New_Type.M_Align; New_Type.M_Size=N_Pos; Def_Type[++Type_Num]=New_Type; Name_to_Type[N_Type_Name]=&Def_Type[Type_Num]; } void Create_New_Elem(string N_Elem_Type,string N_Elem_Name){ Elem New_Elem; New_Elem.cls(); int T_Size=Name_to_Type[N_Elem_Type]->M_Size; int T_Align=Name_to_Type[N_Elem_Type]->M_Align; if(Addr_Pos%T_Align) Addr_Pos=(Addr_Pos/T_Align+1)*T_Align; New_Elem.Addr=Addr_Pos; New_Elem.Elem_Type=*Name_to_Type[N_Elem_Type]; New_Elem.Name=N_Elem_Name; Def_Elem[++Elem_Num]=New_Elem; Name_to_Elem[N_Elem_Name]=&Def_Elem[Elem_Num]; Addr_to_Elem[{Addr_Pos,Addr_Pos+T_Size-1}]=&Def_Elem[Elem_Num]; Addr_Pos+=T_Size; } int Visit_Elem(string N_Elem_Name){ queue<string> Que_Elem_Name; string Tool; Tool.clear(); for(int i=0;i<N_Elem_Name.size();i++){ if(N_Elem_Name[i]=='.'){ Que_Elem_Name.push(Tool); Tool.clear(); } else Tool+=N_Elem_Name[i]; } Que_Elem_Name.push(Tool); int N_Pos=Name_to_Elem[Que_Elem_Name.front()]->Addr; Type N_Type=Name_to_Elem[Que_Elem_Name.front()]->Elem_Type; Que_Elem_Name.pop(); while(!Que_Elem_Name.empty()){ string N_Name=Que_Elem_Name.front(); Que_Elem_Name.pop(); vector<string>::iterator N_It1=N_Type.M_Name.begin(); vector<Type*>::iterator N_It2=N_Type.M_Type.begin(); for(;N_It1!=N_Type.M_Name.end();N_It1++,N_It2++){ if(N_Pos%(*N_It2)->M_Align) N_Pos=(N_Pos/(*N_It2)->M_Align+1)*(*N_It2)->M_Align; if(*N_It1==N_Name){ N_Type=**N_It2; break; } else N_Pos+=(*N_It2)->M_Size; } } return N_Pos; } string Visit_Addr(int N_Goal_Addr){ if(N_Goal_Addr>=Addr_Pos) return "ERR"; Elem N_Elem; map<pii,Elem*>::iterator N_It=Addr_to_Elem.begin(); for(;N_It!=Addr_to_Elem.end();N_It++){ if(N_Goal_Addr>=(*N_It).first.first&&N_Goal_Addr<=(*N_It).first.second){ N_Elem=*((*N_It).second); break; } } int N_Goal_Pos=N_Goal_Addr-N_Elem.Addr,N_Pos_ST=0,N_Pos_ED; Type N_Type=N_Elem.Elem_Type; string N_Elem_Name; N_Elem_Name.clear(); N_Elem_Name+=N_Elem.Name; while(!N_Type.M_Name.empty()){ vector<string>::iterator N_It1=N_Type.M_Name.begin(); vector<Type*>::iterator N_It2=N_Type.M_Type.begin(); for(;N_It2!=N_Type.M_Type.end();N_It1++,N_It2++){ N_Pos_ED=N_Pos_ST+(*N_It2)->M_Size; if(N_Goal_Pos>=N_Pos_ST&&N_Goal_Pos<N_Pos_ED){ N_Elem_Name+='.'+(*N_It1); N_Type=**N_It2; break; } else{ if(N_It2+1==N_Type.M_Type.end()) return "ERR"; int T_Align=(*(N_It2+1))->M_Align; if(N_Pos_ED%T_Align) N_Pos_ED=(N_Pos_ED/T_Align+1)*T_Align; if(N_Goal_Pos<N_Pos_ED) return "ERR"; N_Pos_ST=N_Pos_ED; } } } if(N_Elem_Name=="") return "ERR"; return N_Elem_Name; } signed main(){ cin>>n; Init(); for(;n;n--){ int op; cin>>op; if(op==1){ string New_Type_Name; int New_Type_Num; cin>>New_Type_Name>>New_Type_Num; for(int i=1;i<=New_Type_Num;i++) cin>>New_Type_Meb_Type[i]>>New_Type_Meb_Name[i]; Create_New_Type(New_Type_Name,New_Type_Num,New_Type_Meb_Type,New_Type_Meb_Name); cout<<Def_Type[Type_Num].M_Size<<' '<<Def_Type[Type_Num].M_Align<<'\n'; } else if(op==2){ string New_Elem_Type,New_Elem_Name; cin>>New_Elem_Type>>New_Elem_Name; Create_New_Elem(New_Elem_Type,New_Elem_Name); cout<<Def_Elem[Elem_Num].Addr<<'\n'; } else if(op==3){ string N_Elem_Name; cin>>N_Elem_Name; cout<<Visit_Elem(N_Elem_Name)<<'\n'; } else{ int N_Goal_Addr; cin>>N_Goal_Addr; cout<<Visit_Addr(N_Goal_Addr)<<'\n'; } } return 0; }
-
T4
题目一眼具有单调性,考虑二分天数 \(x\)。
在
check
中,我们可以通过再一次二分求出每个节点最晚的种树时间 \(t_i\)。如何具体进行操作?
我们有节点 \(u\) 在时刻 \([l,r]\) 中的树高度表达式:
\[\sum_{i=l}^{r} \max(b_u+c_u \times i,1) \]对于 \(c_u \ge 0\),原式可化为
\[b_u \times (r-l+1)+c_u \times \dfrac{(l+r) \times (r-l+1)}{2} \]若 \(c_u<0\),则我们令 \(t=\dfrac{1-b_u}{c_u}\)。
此时若 \(t<l\),则原式可化为
\[r-l+1 \]若 \(t>r\),则原式可化为
\[b_u \times (r-l+1)+c_u \times \dfrac{(l+r) \times (r-l+1)}{2} \]若 \(l \le t \le r\),则原式可化为
\[b_u \times (t-l+1)+c_u \times \dfrac{(l+t) \times (t-l+1)}{2}+(r-t) \](应该很好理解吧 qwq)
于是,我们对于二分出的 \(mid\) 值,代入上式计算,若其 \(\ge\) 当前的 \(a_i\) 则可以往上二分,否则往下二分。
当然若从第一时刻开始种树都无法满足当前要求就直接弃疗即可。
求出 \(t_i\) 后,考虑一种贪心策略,即按 \(t_i\) 从小到大的顺序考虑每个节点,若未种树,则将根节点到它的路径上所有未种树的节点全种上树。贪心的正确性(似乎)是显然的。
于是按照此贪心策略模拟种树即可。
注意开
__int128
。#include<bits/stdc++.h> #define i128 __int128 using namespace std; int n; long long a[100031]; int b[100031],c[100031]; vector<int> G[200031]; bool vis[100031]; int f[100031]; i128 t[100031]; int p[100031]; int top,stk[100031]; bool cmp(int x,int y){ return t[x]<t[y]; } void dfs(int x,int fa){ f[x]=fa; for(auto i:G[x]){ if(i==fa) continue; dfs(i,x); } } i128 calc(int x,i128 l,i128 r){ if(c[x]>=0) return (r-l+1)*b[x]+(l+r)*(r-l+1)/2*c[x]; i128 tt=(1-b[x])/c[x]; if(tt<l) return r-l+1; else if(tt>r) return (r-l+1)*b[x]+(l+r)*(r-l+1)/2*c[x]; return (tt-l+1)*b[x]+(l+tt)*(tt-l+1)/2*c[x]+r-tt; } bool check(int x){ for(int i=1;i<=n;i++){ if(calc(i,1,x)<a[i]) return 0; int l=0,r=n+1; while(l+1<r){ int mid=(l+r)>>1; if(calc(i,mid,x)>=a[i]) l=mid; else r=mid; } t[i]=l,p[i]=i,vis[i]=0; } sort(p+1,p+n+1,cmp); for(int i=1,tme=0;i<=n;i++){ int now=p[i],top=0; for(;!vis[now];now=f[now]) vis[stk[++top]=now]=1; for(;top;top--) if(t[stk[top]]<++tme) return 0; } return 1; } int main(){ cin>>n; for(int i=1;i<=n;i++) cin>>a[i]>>b[i]>>c[i]; for(int i=1,u,v;i<n;i++){ cin>>u>>v, G[u].push_back(v), G[v].push_back(u); } vis[0]=1; dfs(1,0); int l=n-1,r=1e9+1; while(l+1<r){ int mid=(l+r)>>1; if(check(mid)) r=mid; else l=mid; } cout<<r; return 0; }
-