目錄node
每組數據讀入一個n和n個字符串。定義前2個與末尾2個字母相同能夠鏈接。問使這個環串的平均長度最大。求這個最大值。不存在輸出\(No solution\)。ios
平均值公式:
\[ Average=(E_1+E_2+.....+E_n)/n \]c++
\[ Average*n=(E_1+E_2+...+E_n) \]數組
\[ (E_1-Average)+(E_2-Average)+...+(E_n-Average)=0 \]佈局
那麼能夠二分答案:
\[ (E_1-Ans)+(E_2-Ans)+...+(E_n-Ans)\geq0 \]
而後瞎搞spfa。ui
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cctype> #include<cerrno> #include<cfloat> #include<ciso646> #include<climits> #include<clocale> #include<cmath> #include<csetjmp> #include<csignal> #include<cstdarg> #include<cstddef> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #define E 200010 #define eps 1e-3 using namespace std; inline int read(){ int res=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } //queue<int> q; //set<int> s; //priority_queue<int> q1; //priority_queue<int,vector<int>,greater<int> > q2; //list<int> l; //stack<int> s; int n; string str[100010]; int fir[E],nxt[E],son[E],tot,cnt,Max; double w[E],dis[E],flag; int vis[E]; int f[6666]; void add(int x,int y,double z){++tot;son[tot]=y;nxt[tot]=fir[x];fir[x]=tot;w[tot]=z;} void spfa(int s,int v,double mid){ if(flag==1) return ; vis[s]=v; for(int i=fir[s];i;i=nxt[i]){ int to=son[i]; if(dis[s]+w[i]>dis[to]+mid){ dis[to]=dis[s]+w[i]-mid; if(dis[to]>Max){ flag=1; return ; } if(!vis[to]) spfa(to,v,mid); if(flag) return ; else if(vis[to]==v){ flag=1; return ; } } } vis[s]=0; } bool check(double mid){ flag=0; for(int i=0;i<=cnt;i++) dis[i]=0.0; memset(vis,0,sizeof(vis)); for(int i=1;i<=cnt;i++){ spfa(i,i,mid); if(flag==1) break; } return flag; } int main(){ // freopen("code.in","r",stdin);freopen("code.out","w",stdout); n=read(); while(n!=0){ for(int i=1;i<=n;i++) cin>>str[i]; memset(fir,0,sizeof(fir)); memset(f,0,sizeof(f)); tot=0;cnt=0;Max=0; for(int i=1;i<=n;i++){ int len=str[i].length(); Max=max(Max,len); int a=(str[i][0]-'a')*26+str[i][1]-'a'; int b=(str[i][len-2]-'a')*26+str[i][len-1]-'a'; if(!f[a]) f[a]=++cnt; int A=f[a]; if(!f[b]) f[b]=++cnt; int B=f[b]; add(A,B,(double)len); } Max*=n; double l=0,r=1000,ans=-1,mid; while(l+eps<r){ mid=(l+r)/2; if(check(mid)) l=mid,ans=mid; else r=mid; } if(ans!=-1) printf("%.2lf\n",ans); else puts("No solution"); n=read(); } return 0; }
讀入一個圖,計算最小路徑的總數。費用時間都相同的兩條最小路徑只算一條,輸出不一樣種類的最小路徑數。this
設\[f[i][j]\]表示在i點且已花費j時的最少時間
\[ f[i][j]=Min(f[k][i-Cost(k,i)]+Time(k,i)|For Each Edge(k,i)) \]es5
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cctype> #include<cerrno> #include<cfloat> #include<ciso646> #include<climits> #include<clocale> #include<cmath> #include<csetjmp> #include<csignal> #include<cstdarg> #include<cstddef> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #define E 5010 #define eps 1e-3 using namespace std; inline int read(){ int res=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } //queue<int> q; //set<int> s; //priority_queue<int> q1; //priority_queue<int,vector<int>,greater<int> > q2; //list<int> l; //stack<int> s; int n,m,s,e; int fir[E],nxt[E],son[E],w[E],cost[E],tot; void add(int x,int y,int z,int t){++tot;w[tot]=z;son[tot]=y;nxt[tot]=fir[x];cost[tot]=t;fir[x]=tot;} int dp[105][10005][3],Max,ans,Min=2e9; int vis[105][10005]; struct node{int pos,dis;}; queue<node> q; node make(int x,int y){node pp;pp.pos=x;pp.dis=y;return pp;} void spfa(){ while(!q.empty()) q.pop(); for(int i=1;i<=n;i++){ for(int j=0;j<=10005;j++){ dp[i][j][0]=2e9; dp[i][j][1]=0; } } dp[s][0][0]=0; dp[s][0][1]=1; vis[s][0]=1; q.push(make(s,0)); while(!q.empty()){ int u=q.front().pos,dis=q.front().dis;q.pop(); vis[u][dis]=0; for(int i=fir[u];i;i=nxt[i]){ int to=son[i]; if(dis+w[i]>Max+1) continue ; if(dp[u][dis][0]+cost[i]<dp[to][dis+w[i]][0]){ dp[to][dis+w[i]][0]=dp[u][dis][0]+cost[i]; dp[to][dis+w[i]][1]=1; if(vis[to][dis+w[i]]==0){ vis[to][dis+w[i]]=1; q.push(make(to,dis+w[i])); } } } } } int main(){ // freopen("code.in","r",stdin);freopen("code.out","w",stdout); n=read();m=read();s=read();e=read(); for(int i=1;i<=m;i++){ int x=read(),y=read(),z=read(),t=read(); add(x,y,z,t); add(y,x,z,t); } Max=(n-1)*100+5; spfa(); for(int i=0;i<=Max;i++){ if(!dp[e][i][1]) continue ; if(dp[e][i][0]<Min){ ans++; Min=dp[e][i][0]; } } write(ans);putchar('\n'); return 0; }
讀入一個有向圖,求圖中最小環的最小平均值時多少。spa
固然食用二分+spfa啦。.net
基本思路同#10082. 「一本通 3.3 例 1」Word Rings
平均值公式:
\[ Average=(E_1+E_2+.....+E_n)/n \]
\[ Average*n=(E_1+E_2+...+E_n) \]
\[ (E_1-Average)+(E_2-Average)+...+(E_n-Average)=0 \]
那麼能夠二分答案:
\[ (E_1-Ans)+(E_2-Ans)+...+(E_n-Ans)\geq0 \]
而後瞎搞spfa。
但此次求最小值。
改一改符號就行了。
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cctype> #include<cerrno> #include<cfloat> #include<ciso646> #include<climits> #include<clocale> #include<cmath> #include<csetjmp> #include<csignal> #include<cstdarg> #include<cstddef> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #define E 20010 #define eps 1e-10 using namespace std; inline int read(){ int res=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } //queue<int> q; //set<int> s; //priority_queue<int> q1; //priority_queue<int,vector<int>,greater<int> > q2; //list<int> l; //stack<int> s; int n,m; int fir[E],nxt[E],son[E],tot; double w[E],Max; void add(int x,int y,double z){++tot;nxt[tot]=fir[x];son[tot]=y;fir[x]=tot;w[tot]=z;} double dis[E],flag; int vis[E]; int spfa(int s,double mid){ vis[s]=1; for(int i=fir[s];i;i=nxt[i]){ int to=son[i]; if(dis[s]+w[i]-mid<dis[to]){ dis[to]=dis[s]+w[i]-mid; if(vis[to]||spfa(to,mid)){vis[s]=0;return 1;} } } vis[s]=0; return 0; } bool check(double mid){ for(int i=0;i<=n;i++) dis[i]=0.0; memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++){ if(spfa(i,mid)==1) return 1; } return 0; } int main(){ n=read();m=read(); for(int i=1;i<=m;i++){ int x=read(),y=read();double z; cin>>z; add(x,y,(double)z); } double l=-1e7,r=1e7,mid,ans; while(l+eps<r){ mid=(l+r)/2; if(check(mid)) r=mid-eps,ans=mid; else l=mid+eps; } printf("%.8lf\n",ans); return 0; }
如今 John 想借助這些蟲洞來回到過去(在出發時刻以前回到出發點),請你告訴他能辦到嗎。 John 將向你提供 F 個農場的地圖。
固然食用spfa啦。
固然,由於我懶,因此將上一題代碼改一改就行了呀。
注意建雙向邊。
注意建負邊。
check時只須要傳入參數0就行了。
由於又沒有讓你求平均值QWQ
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cctype> #include<cerrno> #include<cfloat> #include<ciso646> #include<climits> #include<clocale> #include<cmath> #include<csetjmp> #include<csignal> #include<cstdarg> #include<cstddef> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #define E 20010 #define eps 1e-10 using namespace std; inline int read(){ int res=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } //queue<int> q; //set<int> s; //priority_queue<int> q1; //priority_queue<int,vector<int>,greater<int> > q2; //list<int> l; //stack<int> s; int n,m; int fir[E],nxt[E],son[E],tot; double w[E],Max; void add(int x,int y,double z){++tot;nxt[tot]=fir[x];son[tot]=y;fir[x]=tot;w[tot]=z;} double dis[E],flag; int vis[E]; int spfa(int s,double mid){ vis[s]=1; for(int i=fir[s];i;i=nxt[i]){ int to=son[i]; if(dis[s]+w[i]-mid<dis[to]){ dis[to]=dis[s]+w[i]-mid; if(vis[to]||spfa(to,mid)){vis[s]=0;return 1;} } } vis[s]=0; return 0; } bool check(double mid){ for(int i=0;i<=n;i++) dis[i]=0.0; memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++){ if(spfa(i,mid)==1) return 1; } return 0; } int main(){ int T,W; T=read(); while(T--){ n=read();m=read();W=read(); tot=0; memset(fir,0,sizeof(fir)); for(int i=1;i<=m;i++){ int x=read(),y=read();double z; cin>>z; add(x,y,(double)z); add(y,x,(double)z); } for(int i=1;i<=W;i++){ int x=read(),y=read();double z; cin>>z; add(x,y,-z); } if(check(0)) puts("YES"); else puts("NO"); } return 0; }
給你一個圖,問從源點到每一個節點的最短路徑分別是多少。
若是存在負權迴路,只輸出一行 -1;若是不存在負權迴路,再求出一個點 S 到每一個點的最短路的長度。若是 S 與這個點不連通,則輸出 NoPath
。
固然食用spfa啦。
先跑一下非源點的。萬一數據卡你其餘有環呢?
而後再跑一次源點。得出Ans
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cctype> #include<cerrno> #include<cfloat> #include<ciso646> #include<climits> #include<clocale> #include<cmath> #include<csetjmp> #include<csignal> #include<cstdarg> #include<cstddef> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #define E 2000010 #define eps 1e-10 #define ll long long using namespace std; inline ll read(){ ll res=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(ll x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } //queue<ll> q; //set<ll> s; //priority_queue<ll> q1; //priority_queue<ll,vector<ll>,greater<ll> > q2; //list<ll> l; //stack<ll> s; ll n,m; ll fir[E],nxt[E],son[E],tot; double w[E],Max; void add(ll x,ll y,double z){++tot;nxt[tot]=fir[x];son[tot]=y;fir[x]=tot;w[tot]=z;} double dis[E],flag; ll vis[E]; queue<int> q; int tt[E]; ll spfa(ll s){ vis[s]=1; q.push(s); while(!q.empty()){ int u=q.front();q.pop(); for(ll i=fir[u];i;i=nxt[i]){ ll to=son[i]; if(dis[u]+w[i]<dis[to]){ dis[to]=dis[u]+w[i]; tt[to]++; if(tt[to]>n+1){ puts("-1"); exit(0); } if(vis[to]==0){ vis[to]=1; q.push(to); } } } vis[u]=0; } return 0; } ll st[E]; int main(){ ll T=1,S; while(T--){ n=read();m=read();S=read(); tot=0; memset(fir,0,sizeof(fir)); for(ll i=1;i<=m;i++){ ll x=read(),y=read();double z; cin>>z; add(x,y,(double)z); } for(ll i=0;i<=n;i++) dis[i]=2e18; dis[S]=0; memset(vis,0,sizeof(vis)); spfa(2); for(ll i=0;i<=n;i++) dis[i]=2e18; dis[S]=0; memset(vis,0,sizeof(vis)); spfa(S); for(ll i=1;i<=n;i++){ if(i==S) puts("0"); else if(dis[i]>=2e18) puts("NoPath"); else{ printf("%.0lf\n",dis[i]); } } } return 0; }
從\(0\sim 5\times 10^4\)中選出儘可能少的整數,使每一個區間\([a_i,b_i]\)內都有至少\(c_i\)個數被選出。
固然食用spfa啦。
設\(s[k]\)表示0~k中至少選多少個整數。根據題意可得:
\[ s[b_i]-s[a_i-1]\geq c_i \]
\[ s[k]-s[k-1]\geq0 \]
\[ s[k]-s[k-1]\leq1 \]
也就是:
\[ s[k-1]-s[k]\geq-1 \]
那麼跑一次最長路就行了。
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cctype> #include<cerrno> #include<cfloat> #include<ciso646> #include<climits> #include<clocale> #include<cmath> #include<csetjmp> #include<csignal> #include<cstdarg> #include<cstddef> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #define E 2000010 #define eps 1e-10 #define ll long long using namespace std; inline ll read(){ ll res=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(ll x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } //queue<ll> q; //set<ll> s; //priority_queue<ll> q1; //priority_queue<ll,vector<ll>,greater<ll> > q2; //list<ll> l; //stack<ll> s; ll n,m; ll fir[E],nxt[E],son[E],tot; double w[E]; void add(ll x,ll y,double z){++tot;nxt[tot]=fir[x];son[tot]=y;fir[x]=tot;w[tot]=z;} double dis[E],flag; ll vis[E]; queue<int> q; int tt[E]; ll spfa(ll s){ vis[s]=1; q.push(s); while(!q.empty()){ int u=q.front();q.pop(); for(ll i=fir[u];i;i=nxt[i]){ ll to=son[i]; if(dis[u]+w[i]>dis[to]){ dis[to]=dis[u]+w[i]; tt[to]++; if(tt[to]>n+1){ puts("-1"); exit(0); } if(vis[to]==0){ vis[to]=1; q.push(to); } } } vis[u]=0; } return 0; } ll st[E],Min,Max; int main(){ n=read(); Max=-1;Min=2e9; for(int i=1;i<=n;i++){ ll x=read(),y=read(),z=read(); add(x-1,y,z); Max=max(Max,y); Min=min(Min,x-1); } for(int i=Min;i<=Max;i++){ add(i,i+1,0); add(i+1,i,-1); } for(int i=Min;i<=Max;i++) dis[i]=-2e9; memset(vis,0,sizeof(vis)); dis[Min]=0; spfa(Min); printf("%.0lf\n",dis[Max]); return 0; }
\(、、R(0)、R(1)、R(2)...R(23)\)表示第x個時刻須要\(R(x)\)個出納員,有n個出納員申請工做,第\(i\)個出納員從\(t_i\)時刻開始工做\(8\)小時,問至少須要多少出納員?
設\(x[i]\)表示第i時刻實際上須要僱傭\(x[i]\)人,\(r[i]\)爲第i時刻至少須要\(r[i]\)我的。
\[ x[i-7]+x[i-6]+x[i-5]+x[i-4]+x[i-3]+x[i-2]+x[i-1]+x[i]\geq r[i] \]
設\(s[i]=x[1]+x[2]+x[3]+...+x[i]\),可得:
\[ s[i]-s[i-1]\geq0 \]
\[ s[i-1]-s[i]\geq-num[i] \]
\[ s[i]-s[i-8]\geq r[i] \]
\[ s[i]-s[i+16]\geq r[i]-s[23] \]
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cctype> #include<cerrno> #include<cfloat> #include<ciso646> #include<climits> #include<clocale> #include<cmath> #include<csetjmp> #include<csignal> #include<cstdarg> #include<cstddef> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #define E 2000010 #define eps 1e-10 #define ll long long using namespace std; inline ll read(){ ll res=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(ll x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } //queue<ll> q; //set<ll> s; //priority_queue<ll> q1; //priority_queue<ll,vector<ll>,greater<ll> > q2; //list<ll> l; //stack<ll> s; ll n,m; ll fir[E],nxt[E],son[E],tot; int w[E]; void add(ll x,ll y,ll z){++tot;nxt[tot]=fir[x];son[tot]=y;fir[x]=tot;w[tot]=z;} int dis[E],flag; ll vis[E]; queue<int> q; int tt[E]; ll spfa(ll s){ memset(dis,63,sizeof(dis)); memset(tt,0,sizeof(tt)); memset(vis,0,sizeof(vis)); dis[24]=0; vis[24]=1; q.push(24); while(!q.empty()){ int u=q.front();q.pop(); for(ll i=fir[u];i;i=nxt[i]){ ll to=son[i]; if(dis[u]+w[i]<dis[to]){ dis[to]=dis[u]+w[i]; tt[to]++; if(tt[to]>n+1){ return 0; } if(vis[to]==0){ vis[to]=1; q.push(to); } } } vis[u]=0; } return dis[0]==-s; } ll T,r[E],Min,Max,s[E],num[E]; void work(int x){ memset(fir,0,sizeof(fir));tot=0; for(register int i=1;i<=24;i++) add(i,i-1,0),add(i-1,i,num[i]); for(register int i=8;i<=24;i++) add(i,i-8,-r[i]); for(register int j=1;j<=7;j++) add(j,j+16,x-r[j]); add(24,0,-x); } int main(){ T=read(); while(T--){ for(int i=1;i<=24;i++){ r[i]=read();num[i]=0; } n=read(); for(int i=1;i<=n;i++){ int t=read();t++; num[t]++; } int l=0,r=n,ans=2e9; while(l<=r){ int mid=(l+r)/2; work(mid); if(spfa(mid)) ans=mid,r=mid-1; else l=mid+1; } if(ans==2e9) puts("No Solution"); else write(ans),putchar('\n'); } return 0; }
知足條件:
若是 X=1.表示第 A 個小朋友分到的糖果必須和第 B 個小朋友分到的精果同樣多。
若是 X=2,表示第 A 個小朋友分到的糖果必須少於第 B 個小朋友分到的糖果。
若是 X=3,表示第 A 個小朋友分到的糖果必須很多於第 B 個小朋友分到的糖果。
若是 X=4,表示第 A 個小朋友分到的糖果必須多於第 B 個小朋友分到的糖果。
若是 X=5,表示第 A 個小朋友分到的糖果必須很少於第 B 個小朋友分到的糖果。
求至少須要準備的糖果數?
若是 X=1
\[ B=A \]
若是 X=2
\[ B+1\ge A \]
若是 X=3
\[ A\ge B \]
若是 X=4
\[ A-1\ge B \]
若是 X=5
\[ B \ge A \]
那麼就行了嘛:
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cctype> #include<cerrno> #include<cfloat> #include<ciso646> #include<climits> #include<clocale> #include<cmath> #include<csetjmp> #include<csignal> #include<cstdarg> #include<cstddef> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #define E 300010 #define eps 1e-10 #define ll long long #pragma GCC optimize(2) using namespace std; inline ll read(){ ll res=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(ll x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } //queue<ll> q; //set<ll> s; //priority_queue<ll> q1; //priority_queue<ll,vector<ll>,greater<ll> > q2; //list<ll> l; //stack<ll> s; ll n,k; ll fir[E],nxt[E],son[E],w[E],tot,inf,ans; inline void add(register ll x,register ll y,register ll z){ ++tot; w[tot]=z; nxt[tot]=fir[x]; fir[x]=tot; son[tot]=y; } ll dis[E],vis[E],tt[E]; deque<ll> q; inline void spfa(){ memset(dis,0,sizeof(dis)); memset(tt,0,sizeof(tt)); memset(vis,0,sizeof(vis));inf=dis[0]; dis[0]=0;vis[0]=1; while(!q.empty()) q.pop_front(); q.push_back(0); while(!q.empty()){ register ll u=q.front();q.pop_front(); vis[u]=0; for(register ll i=fir[u];i;i=nxt[i]){ register ll to=son[i]; if(dis[to]<dis[u]+w[i]){ tt[to]++; dis[to]=dis[u]+w[i]; if(tt[to]>n+1){ puts("-1"); exit(0); } if(!vis[to]){ vis[to]=1; if(!q.empty()&&dis[to]<dis[q.front()]) q.push_front(to); else q.push_back(to); } } } } } int main(){ n=read();k=read(); for(register ll i=1;i<=k;i++){ ll x=read(),a=read(),b=read(); if(a==b&&(x==2||x==4)){ puts("-1"); return 0; } if(x==1) add(a,b,0),add(b,a,0); if(x==2) add(a,b,1); if(x==3) add(b,a,0); if(x==4) add(b,a,1); if(x==5) add(a,b,0); } for(register ll i=1;i<=n;i++) add(0,i,1); spfa(); for(register ll i=1;i<=n;i++){ ans+=dis[i]; } write(ans);putchar('\n'); return 0; }
有些奶牛是好基友,它們但願彼此之間的距離小於等於某個數。有些奶牛是情敵,它們但願彼此之間的距離大於等於某個數。
若是兩隻奶牛是好基友,那麼:
\[ A-B\leq D \]
若是兩隻奶牛是情敵,那麼:
\[ A-B\ge D \]
即:
\[ D\leq A-B \]
也就是:
\[ B-A\leq -D \]
直接上代碼:
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cctype> #include<cerrno> #include<cfloat> #include<ciso646> #include<climits> #include<clocale> #include<cmath> #include<csetjmp> #include<csignal> #include<cstdarg> #include<cstddef> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #define E 300010 #define eps 1e-10 #define ll long long #pragma GCC optimize(2) using namespace std; inline ll read(){ ll res=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(ll x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } //queue<ll> q; //set<ll> s; //priority_queue<ll> q1; //priority_queue<ll,vector<ll>,greater<ll> > q2; //list<ll> l; //stack<ll> s; ll n,k; ll fir[E],nxt[E],son[E],w[E],tot,inf,ans; inline void add(register ll x,register ll y,register ll z){ ++tot; w[tot]=z; nxt[tot]=fir[x]; fir[x]=tot; son[tot]=y; } ll dis[E],vis[E],tt[E]; deque<ll> q; inline void spfa(int s){ memset(dis,63,sizeof(dis)); memset(tt,0,sizeof(tt)); memset(vis,0,sizeof(vis));inf=dis[0]; dis[s]=0;vis[s]=1; while(!q.empty()) q.pop_front(); q.push_back(s); while(!q.empty()){ register ll u=q.front();q.pop_front(); vis[u]=0; for(register ll i=fir[u];i;i=nxt[i]){ register ll to=son[i]; if(dis[to]>dis[u]+w[i]){ tt[to]++; dis[to]=dis[u]+w[i]; if(tt[to]>n+1){ puts("-1"); exit(0); } if(!vis[to]){ vis[to]=1; if(!q.empty()&&dis[to]<dis[q.front()]) q.push_front(to); else q.push_back(to); } } } } } int k1,k2; int main(){ n=read();k1=read();k2=read(); for(register ll i=1;i<=k1;i++){ ll x=read(),y=read(),z=read(); add(x,y,z); } for(register ll i=1;i<=k2;i++){ ll x=read(),y=read(),z=read(); add(y,x,-z); } spfa(1); ans=dis[n]; for(int i=1;i<=n;i++) spfa(i); if(ans>=inf) puts("-2"); else write(ans),putchar('\n'); return 0; }
這是一道模板題。
給定Q個操做:
1 i x
:給定 \(i,x\),將 \(a[i]\) 加上 \(x\);2 l r
:給定 \(l,r\),求 \(\sum_{i=l}^ra[i]\) 的值(換言之,求 \(a[l]+a[l+1]+\dots+a[r]\) 的值)。模板題呀。
#include<bits/stdc++.h> #define ll long long using namespace std; ll n,m; ll a[5000010]; void add(ll x,ll y){ for(ll i=x;i<=n;i+=i&(-i)){ a[i]+=y; } } ll getsum(ll x){ ll sum=0; for(ll i=x;i;i-=i&(-i)){ sum+=a[i]; } return sum; } int main(){ scanf("%lld%lld",&n,&m); for(ll i=1;i<=n;i++){ ll x;scanf("%lld",&x); add(i,x); } for(ll i=1;i<=m;i++){ ll type; scanf("%lld",&type); if(type==1){ ll x,k; scanf("%lld%lld",&x,&k); add(x,k); } if(type==2){ ll x,y; scanf("%lld%lld",&x,&y); printf("%lld\n",getsum(y)-getsum(x-1)); } } }
給定 \(n\) 個點,定義每一個點的等級是在該點左下方(含正左、正下)的點的數目,試統計每一個等級有多少個點。
這不就是裸的樹狀數組嗎?
題目都按順序(y的增序)。。。
#include<bits/stdc++.h> using namespace std; inline int read(){ char ch=getchar();int res=0,f=1; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } int n,x,y,ans[1500010]; int a[1500010]; void add(int x,int y){ for(int i=x;i<=1500000;i+=i&(-i)){ a[i]+=y; } } int getsum(int x){ int sum=0; for(int i=x;i;i-=i&(-i)){ sum+=a[i]; } return sum; } int main(){ n=read(); for(int i=1;i<=n;i++){ x=read();y=read(); int t=getsum(x+1); ans[t]++; add(x+1,1); } for(int i=0;i<n;i++){ write(ans[i]);putchar('\n'); } return 0; }
A
,接下來是一個數 \(m\),表示年級主任如今在第 \(m\) 節車箱;B
,接下來是兩個數 \(m,p\),表示在第 \(m\) 節車箱有 \(p\) 名學生上車;C
,接下來是兩個數 \(m,p\),表示在第 \(m\) 節車箱有 \(p\) 名學生下車。固然是樹狀數組啦。。。
若是字母爲 A
,那麼\(getsum(m)\)
若是字母爲 B
,那麼\(add(m,p)\)
若是字母爲 C
,那麼\(add(m,-p)\)
好了呀。。。
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cctype> #include<cerrno> #include<cfloat> #include<ciso646> #include<climits> #include<clocale> #include<cmath> #include<csetjmp> #include<csignal> #include<cstdarg> #include<cstddef> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> using namespace std; inline int read(){ int res=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } //queue<int> q; //set<int> s; //priority_queue<int> q1; //priority_queue<int,vector<int>,greater<int> > q2; //list<int> l; //stack<int> s; int n,k; int c[500010]; void add(int x,int y){ for(int i=x;i<=n;i+=i&(-i)){ c[i]+=y; } } int getsum(int x){ int sum=0; for(int i=x;i;i-=i&(-i)){ sum+=c[i]; } return sum; } int main(){ // freopen("code.in","r",stdin);freopen("code.out","w",stdout); n=read();k=read(); for(int i=1;i<=k;i++){ char A;cin>>A; int m,p; if(A=='A'){ m=read(); write(getsum(m));putchar('\n'); }else if(A=='B'){ m=read();p=read(); add(m,p); }else if(A=='C'){ m=read();p=read(); add(m,-p); } } return 0; }
有一個 \(n\) 個元素的數組,每一個元素初始均爲 \(0\)。有 \(m\) 條指令,要麼讓其中一段連續序列數字反轉——\(0\) 變 \(1\),\(1\) 變 \(0\)(操做 \(1\)),要麼詢問某個元素的值(操做 \(2\))。
固然是樹狀數組啦。。。
這裏介紹C++的一大利器——位運算。
&
在C++裏叫作與運算。應該差很少吧。。大概就是這樣的:(按一個個位運算)
1&1=1 0&1=0 1&0=0 0&0=0
|
在C++裏叫或運算
0|1=1 1|0=1 1|1=1 0|0=0
^
在C++裏叫異或(xor)
0^0=0 1^0=1 0^1=1 1^1=0
~
在C++裏叫取反
顧名思義。。。
~1=0 ~0=1
而後你就會發現這道題能夠用C++的異或+樹狀數組解決。
利用樹狀數組,作一個異或前綴和。而後在輸出時異或一遍就行了。
(這道題的1操做就至關於異或1)
(然而咱們知道x xor 1 xor 1仍是等於x)
(因此對於每一個1操做只須要先把l以前的xor 1,而後r+1以前的xor 1)
(對於每一個2操做只須要把前面通通xor一遍)
你就完美的解決了這道題
#include<bits/stdc++.h> using namespace std;//醜陋無比的頭文件終於結束 inline int read(){ int res=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; }//讀入 inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } }//輸出 int n,k; int c[500010];//不解釋 void add(int x,int y){//修改 for(int i=x;i<=n;i+=i&(-i)){ c[i]^=y;//異或前綴和 } } int getsum(int x){//詢問 int sum=0; for(int i=x;i;i-=i&(-i)){ sum^=c[i];//詢問異或 } return sum;//返回啊 } int main(){ n=read();k=read();//讀入 for(int i=1;i<=k;i++){ char A;cin>>A; int m,p; if(A=='1'){//操做1 m=read();p=read(); add(m,1);//先將l以前的xor 1 add(p+1,1);//而後把r+1以前的xor 1 //那麼l以前的數通通 xor 1 xor 1,抵消 }else if(A=='2'){ m=read(); write(getsum(m));putchar('\n');//詢問輸出 } } return 0;//結束了。。。 }
這是一道模板題。
給出一個 \(n\times m\) 的零矩陣 \(A\),你須要完成以下操做:
1 x y k
:表示元素 \(A_{x,y}\) 自增 \(k\);2 a b c d
:表示詢問左上角爲 \((a,b)\),右下角爲 \((c,d)\) 的子矩陣內全部數的和。固然是樹狀數組啦。。。
模板題。不介紹。
#include<bits/stdc++.h> #define ll long long using namespace std; ll n,m; ll a[5010][5010]; ll lowbit(ll x){ return (x&-x); } void add(ll x,ll y,ll k){ for(ll i=x;i<=n;i+=lowbit(i)){ for(ll j=y;j<=m;j+=lowbit(j)){ a[i][j]+=k; } } } ll getsum(ll x,ll y){ ll sum=0; for(ll i=x;i>0;i-=lowbit(i)){ for(ll j=y;j>0;j-=lowbit(j)){ sum+=a[i][j]; } } return sum; } int main(){ scanf("%lld%lld",&n,&m); ll type; while(scanf("%lld",&type)!=EOF){ if(type==1){ ll x,y,k; scanf("%lld%lld%lld",&x,&y,&k); add(x,y,k); } if(type==2){ ll x1,y1,x2,y2; scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2); printf("%lld\n",getsum(x2,y2)-getsum(x2,y1-1)-getsum(x1-1,y2)+getsum(x1-1,y1-1)); } } return 0; }
這是一道模板題。
輸入一串數字,給你 \(M\) 個詢問,每次詢問就給你兩個數字 \(X,Y\),要求你說出 \(X\) 到 \(Y\) 這段區間內的最大數。
模板題。不介紹。
RMQ問題
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cstring> #include<cmath> using namespace std; inline int read(){ char ch=getchar();int res=0,f=1; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(int zx){ if(zx<0) zx=-zx,putchar('-'); if(zx<10) putchar(zx+'0'); else{ write(zx/10); putchar(zx%10+'0'); } } int n,m,a[100010],f[100010][20]; void ST(){ for(int i=1;i<=n;i++) f[i][0]=a[i]; for(int j=1;(1<<j)<=n;j++){ for(int i=1;i+(1<<j)-1<=n;i++){ f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); } } } int RMQ(int l,int r){ int k=0; while((1<<(k+1))<=r-l+1) k++; return max(f[l][k],f[r-(1<<k)+1][k]); } int main(){ n=read();m=read(); for(int i=1;i<=n;i++) a[i]=read(); ST(); for(int i=1;i<=m;i++){ int l=read(),r=read(); write(RMQ(l,r)); putchar('\n'); } return 0; }
首先,他們面前會有一排共 \(n\) 個數,它們比賽看誰能最早把每連續 \(k\) 個數中最大和最小值寫下來,固然,這些機器人運算速度都很快,它們比賽的是誰寫得快。
模板題。不介紹。
RMQ問題分別作一個最大值與最小值。
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cstring> #include<cmath> #define ll long long using namespace std; inline ll read(){ char ch=getchar();ll res=0,f=1; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(ll zx){ if(zx<0) zx=-zx,putchar('-'); if(zx<10) putchar(zx+'0'); else{ write(zx/10); putchar(zx%10+'0'); } } ll n,m,a[100010],f[100010][20],f2[100010][20]; void ST(){ for(ll i=1;i<=n;i++) f[i][0]=a[i]; for(ll j=1;(1<<j)<=n;j++) { for(ll i=1;i+(1<<j)-1<=n;i++) { f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); } } } ll RMQ(ll l,ll r){ ll k=0; while((1<<(k+1))<=r-l+1) k++; return max(f[l][k],f[r-(1<<k)+1][k]); } void ST2(){ for(ll i=1;i<=n;i++) f2[i][0]=a[i]; for(ll j=1;(1<<j)<=n;j++) { for(ll i=1;i+(1<<j)-1<=n;i++) { f2[i][j]=min(f2[i][j-1],f2[i+(1<<(j-1))][j-1]); } } } ll RMQ2(ll l,ll r){ ll k=0; while((1<<(k+1))<=r-l+1) k++; return min(f2[l][k],f2[r-(1<<k)+1][k]); } int main(){ n=read();m=read(); for(ll i=1;i<=n;i++) a[i]=read(); ST();ST2(); for(ll i=1;i<=n-m+1;i++){ write(RMQ(i,i+m-1)); putchar(' '); write(RMQ2(i,i+m-1)); putchar('\n'); } return 0; }
定義完美序列:一段連續的序列知足序列中的數互不相同。
想知道區間 \([L,R]\) 之間最長的完美序列長度。
設\(las[x]\)表示盈利\(x\)最近出現位置。
設\(st[i]\)表示以第\(i\)個數結尾的最長完美序列的起始位置。
\[st[i]=max(st[i-1],las[a[i]+1])\]
設\(f[i]\)表示以第\(i\)個數結尾的最長完美序列的長度
\[f[i]=i-st[i]+1\]
由\(st\)的遞推式可知,\(st\)的值是一個非遞減的序列。
對於一個詢問區間\([l_i,r_i]\),該區間內的\(st\)值可能會有兩種狀況:
因爲\(st\)的值具備單調性,因此這個邊界能夠經過二分獲得。設求出的邊界爲\(mid\)_i,可得:
\[st[l_i...mid_i-1]<l_i\]
\[st[mid_i...r_i]\ge l_i\]
那麼整個區間\([l_i,r_i]\)的最長完美序列的長度能夠分兩部分來求。
左邊:很顯然爲\(mid_i-l_i\)
右邊:\(MAX(m_i...r_i)\)
因此右邊的長度要使用ST表,即RMQ來求。
整個問題的時間複雜度:
\[O((M+N) \times logN)\]
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cstring> #include<cmath> #define ll long long const int N=2e5+5,M=1e6; using namespace std; inline ll read(){ char ch=getchar();ll res=0,f=1; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(ll zx){ if(zx<0) zx=-zx,putchar('-'); if(zx<10) putchar(zx+'0'); else{ write(zx/10); putchar(zx%10+'0'); } } ll n,m,f[N][20],st[N],las[M<<1]; void ST(){ for(ll j=1;(1<<j)<=n;j++){ for(ll i=1;i+(1<<j)-1<=n;i++){ f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); } } } ll RMQ(ll l,ll r){ ll k=0; while((1<<(k+1))<=r-l+1) k++; return max(f[l][k],f[r-(1<<k)+1][k]); } ll find(ll l,ll r){ if(st[l]==l) return l; if(st[r]<l) return r+1; int L=l,R=r; while(L<=R){ int m=L+R>>1; if(st[m]<l) L=m+1; else R=m-1; } return L; } int main(){ n=read();m=read(); for(ll i=1;i<=n;i++){ int x=read(); st[i]=max(st[i-1],las[x+M]+1); f[i][0]=i-st[i]+1; las[x+M]=i; } ST(); for(ll i=1;i<=m;i++){ ll L,R; L=read();R=read();L++;R++; ll mid=find(L,R),ans=0,tmp; if(mid>L) ans=mid-L; if(mid<=R){ tmp=RMQ(mid,R); ans=max(ans,tmp); } write(ans);putchar('\n'); } return 0; }
給你一大串數字(編號爲 \(1\) 到 \(N\),大小可不必定哦!),在你看過一遍以後,它便消失在你面前,隨後問題就出現了,給你 \(M\) 個詢問,每次詢問就給你兩個數字 \(A,B\),要求你瞬間就說出屬於 \(A\) 到 \(B\) 這段區間內的最大數。
典型的RMQ模板題啦。
先把一開始的一大串數字塞入RMQ。而後詢問就好啦。沒有一點坑。。。
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cstring> #include<cmath> #define ll long long const int N=2e5+5,M=1e6; using namespace std; inline ll read(){ char ch=getchar();ll res=0,f=1; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(ll zx){ if(zx<0) zx=-zx,putchar('-'); if(zx<10) putchar(zx+'0'); else{ write(zx/10); putchar(zx%10+'0'); } } ll n,m,f[N][20],st[N],las[M<<1]; void ST(){ for(ll j=1;(1<<j)<=n;j++){ for(ll i=1;i+(1<<j)-1<=n;i++){ f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); } } } ll RMQ(ll l,ll r){ ll k=0; while((1<<(k+1))<=r-l+1) k++; return max(f[l][k],f[r-(1<<k)+1][k]); } ll find(ll l,ll r){ if(st[l]==l) return l; if(st[r]<l) return r+1; int L=l,R=r; while(L<=R){ int m=L+R>>1; if(st[m]<l) L=m+1; else R=m-1; } return L; } int main(){ n=read(); for(ll i=1;i<=n;i++){ int x=read(); f[i][0]=x; } ST();m=read(); for(ll i=1;i<=m;i++){ ll L,R; L=read();R=read();int ans=RMQ(L,R); write(ans);putchar('\n'); } return 0; }
FJ 準備了 \(Q\) 個可能的牛的選擇和全部牛的身高。他想知道每一組裏面最高和最低的牛的身高差異。
典型的RMQ模板題啦。
先把一開始的一大串數字塞入RMQ。而後詢問就好啦。沒有一點坑。。。
注意RMQ2次就行了啊
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cstring> #include<cmath> #define ll long long const int N=2e5+5,M=1e6; using namespace std; inline ll read(){ char ch=getchar();ll res=0,f=1; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(ll zx){ if(zx<0) zx=-zx,putchar('-'); if(zx<10) putchar(zx+'0'); else{ write(zx/10); putchar(zx%10+'0'); } } ll n,m,f[N][20],st[N],las[M<<1],f2[N][20]; void ST(){ for(ll j=1;(1<<j)<=n;j++){ for(ll i=1;i+(1<<j)-1<=n;i++){ f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); } } } ll RMQ(ll l,ll r){ ll k=0; while((1<<(k+1))<=r-l+1) k++; return max(f[l][k],f[r-(1<<k)+1][k]); } void ST2(){ for(ll j=1;(1<<j)<=n;j++){ for(ll i=1;i+(1<<j)-1<=n;i++){ f2[i][j]=min(f2[i][j-1],f2[i+(1<<(j-1))][j-1]); } } } ll RMQ2(ll l,ll r){ ll k=0; while((1<<(k+1))<=r-l+1) k++; return min(f2[l][k],f2[r-(1<<k)+1][k]); } int main(){ n=read();m=read(); for(ll i=1;i<=n;i++){ int x=read(); f2[i][0]=f[i][0]=x; } ST();ST2(); for(ll i=1;i<=m;i++){ ll L,R; L=read();R=read();int ans=RMQ(L,R)-RMQ2(L,R); write(ans);putchar('\n'); } return 0; }
有\(n\)個客棧,每一個客棧都配有咖啡館。有兩名旅客想住在同色調的客棧中,又想在兩客棧之間的咖啡館中小聚,咖啡館的價錢不能高於\(p\)。
對於 \(100\%\) 的數據,有 \(2\leq n\leq2\times 10^6\),\(0<k\leq10^4\) ,\(0\leq p\leq100\),\(0\leq\) 最低消費 \(\leq100\) 。
\(n\)的範圍那麼大,\(k\)的範圍那麼小。那麼暴力吧。
設\(h_i\)表示目前顏色\(i\)的客棧數量,\(las_i\)表示最近的顏色爲\(i\)的客棧的編號。
而後\(O(n)\)掃一遍就行了啊。
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cstring> #include<cmath> #define ll long long const int N=2e5+5,M=1e6; using namespace std; inline ll read(){ char ch=getchar();ll res=0,f=1; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(ll zx){ if(zx<0) zx=-zx,putchar('-'); if(zx<10) putchar(zx+'0'); else{ write(zx/10); putchar(zx%10+'0'); } } ll n,m,color,price,now,las[N],h[N],sum[N],ans,p; int main(){ n=read();m=read();p=read(); for(ll i=1;i<=n;i++){ color=read(),price=read();//讀入 if(price<=p) now=i;//價錢要小於或等於p if(now>=las[color]) sum[color]=h[color];//若是比上一個顏色相同的近,直接加上方案數 ans+=sum[color];//更新ANS h[color]++;las[color]=i;//更新LAS和H } write(ans);putchar('\n');//輸出 return 0; }
這是一道模板題。
給定Q個操做:
1 i x
:給定 \(i,x\),將 \(a[i]\) 加上 \(x\);2 l r
:給定 \(l,r\),求 \(\sum_{i=l}^ra[i]\) 的值(換言之,求 \(a[l]+a[l+1]+\dots+a[r]\) 的值)。模板題呀。但線段樹能夠過啊。
粘模板了。。。
#include<bits/stdc++.h> #define N 10000000+10 #define ll long long using namespace std; ll n,m,a[N],add[N*4+10]; ll tree[N*4+10]; void pushup(ll id){ tree[id]=tree[id<<1]+tree[(id<<1)|1]; } void build(ll id,ll l,ll r){ if(l==r) tree[id]=a[l]; else{ ll mid=l+((r-l)>>1); build(id<<1,l,mid); build((id<<1)|1,mid+1,r); pushup(id); } } void pushdown(ll id,ll l,ll r){ if(add[id]!=0){ add[id<<1]+=add[id]; add[(id<<1)|1]+=add[id]; ll mid=l+((r-l)>>1); tree[id<<1]+=add[id]*(mid-l+1); tree[(id<<1)|1]+=add[id]*(r-mid); add[id]=0; } } void update(ll id,ll l,ll r,ll ql,ll qr,ll val){ if(ql<=l&&qr>=r){ add[id]+=val; tree[id]+=val*(r-l+1); return ; } pushdown(id,l,r); ll mid=l+((r-l)>>1); if(ql<=mid) update(id<<1,l,mid,ql,qr,val); if(qr>=mid+1) update((id<<1)|1,mid+1,r,ql,qr,val); pushup(id); } ll query(ll id,ll l,ll r,ll ql,ll qr){ if(ql<=l&&qr>=r) return tree[id]; pushdown(id,l,r); ll mid=l+((r-l)>>1); ll ans=0; if(ql<=mid) ans+=query(id<<1,l,mid,ql,qr); if(qr>=mid+1) ans+=query((id<<1)|1,mid+1,r,ql,qr); return ans; } int main(){ scanf("%lld%lld",&n,&m); for(ll i=1;i<=n;i++) scanf("%lld",&a[i]); build(1,1,n); for(ll i=1;i<=m;i++){ ll type; scanf("%lld",&type); if(type==1){ ll x,y,k; scanf("%lld%lld",&y,&k); update(1,1,n,y,y,k); } if(type==2){ ll x,y; scanf("%lld%lld",&x,&y); ll temp=query(1,1,n,x,y); printf("%lld\n",temp); } } return 0; }
這是一道模板題。\r\n\r\n給定數列 \(a[1], a[2], \dots, a[n]\),你須要依次進行 \(q\) 個操做,操做有兩類:
1 l r x
:給定 \(l,r,x\),對於全部 \(i\in[l,r]\),將 \(a[i]\) 加上 \(x\)(換言之,將 \(a[l], a[l+1], \dots, a[r]\) 分別加上 \(x\));2 l r
:給定 \(l,r\),求 \(\sum_{i=l}^ra[i]\) 的值(換言之,求 \(a[l]+a[l+1]+\dots+a[r]\) 的值)。模板題呀。但線段樹能夠過啊。
粘模板了。。。
#include<bits/stdc++.h> #define ll long long using namespace std; ll n,m,a[1000010],add[1000000*4+10]; ll tree[1000000*4+10]; void pushup(ll id){ tree[id]=tree[id<<1]+tree[(id<<1)|1]; } void build(ll id,ll l,ll r){ if(l==r) tree[id]=a[l]; else{ ll mid=l+((r-l)>>1); build(id<<1,l,mid); build((id<<1)|1,mid+1,r); pushup(id); } } void pushdown(ll id,ll l,ll r){ if(add[id]!=0){ add[id<<1]+=add[id]; add[(id<<1)|1]+=add[id]; ll mid=l+((r-l)>>1); tree[id<<1]+=add[id]*(mid-l+1); tree[(id<<1)|1]+=add[id]*(r-mid); add[id]=0; } } void update(ll id,ll l,ll r,ll ql,ll qr,ll val){ if(ql<=l&&qr>=r){ add[id]+=val; tree[id]+=val*(r-l+1); return ; } pushdown(id,l,r); ll mid=l+((r-l)>>1); if(ql<=mid) update(id<<1,l,mid,ql,qr,val); if(qr>=mid+1) update((id<<1)|1,mid+1,r,ql,qr,val); pushup(id); } ll query(ll id,ll l,ll r,ll ql,ll qr){ if(ql<=l&&qr>=r) return tree[id]; pushdown(id,l,r); ll mid=l+((r-l)>>1); ll ans=0; if(ql<=mid) ans+=query(id<<1,l,mid,ql,qr); if(qr>=mid+1) ans+=query((id<<1)|1,mid+1,r,ql,qr); return ans; } int main(){ scanf("%lld%lld",&n,&m); for(ll i=1;i<=n;i++) scanf("%lld",&a[i]); build(1,1,n); for(ll i=1;i<=m;i++){ ll type; scanf("%lld",&type); if(type==1){ ll x,y,k; scanf("%lld%lld%lld",&x,&y,&k); update(1,1,n,x,y,k); } if(type==2){ ll x,y; scanf("%lld%lld",&x,&y); ll temp=query(1,1,n,x,y); printf("%lld\n",temp); } } return 0; }
給定一個正整數數列 \(a_1, a_2, a_3, \cdots , a_n\),每個數都在 \(0\sim p – 1\) 之間。能夠對這列數進行兩種操做:
添加操做:向序列後添加一個數,序列長度變成 \(n + 1\);
詢問操做:詢問這個序列中最後 \(L\) 個數中最大的數是多少。
程序運行的最開始,整數序列爲空。寫一個程序,讀入操做的序列,並輸出詢問操做的答案。
模板題呀。
#include<bits/stdc++.h> #define ll long long #define MAXNUM 200000*4+10 using namespace std; struct node{ ll l,r,lef,rig,c; }tree[MAXNUM]; ll n,m,q,len,las; void build(ll l,ll r){ ll root=++len; tree[root].l=l;tree[root].r=r;tree[root].lef=tree[root].rig=-1; if(l<r){ ll mid=(l+r)/2; tree[root].lef=len+1;build(l,mid); tree[root].rig=len+1;build(mid+1,r); } } void update(ll root,ll x,ll k){ if(tree[root].l==tree[root].r){tree[root].c=k;return ;} ll lef=tree[root].lef,rig=tree[root].rig; ll mid=(tree[root].l+tree[root].r)/2; if(x<=mid) update(lef,x,k); else update(rig,x,k); tree[root].c=max(tree[lef].c,tree[rig].c); } ll query(ll root,ll l,ll r){ if(tree[root].l>=l&&tree[root].r<=r) return tree[root].c; ll lef=tree[root].lef,rig=tree[root].rig; ll mid=(tree[root].l+tree[root].r)/2; if(r<=mid) return query(lef,l,r); else if(mid<l) return query(rig,l,r); else return max(query(lef,l,mid),query(rig,mid+1,r)); } int main(){ scanf("%lld%lld",&m,&q); build(1,m); while(m--){ char s;cin>>s; if(s=='A'){ ll x;scanf("%lld",&x);n++; update(1,n,(x+las)%q); }else{ ll x;scanf("%lld",&x); las=query(1,n-x+1,n); printf("%lld\n",las); } } }
每一次旅行中,花神會選擇一條旅遊路線,它在那一串國家中是連續的一段,此次旅行帶來的開心值是這些國家的喜歡度的總和,固然花神對這些國家的喜歡程序並非恆定的,有時會忽然對某些國家產生反感,使他對這些國家的喜歡度 \(\delta\) 變爲 \(\sqrt \delta\)(多是花神虐爆了那些國家的 OI,從而感到乏味)。
如今給出花神每次的旅行路線,以及開心度的變化,請求出花神每次旅行的開心值。
爲了使時間複雜度下降,咱們能夠發現:\(\sqrt 1=1\)因此,最大數字\(10^9\)操做較少次數便能到\(1\)。因此在操做前判斷一下,若是區間內都是\(1\)便可跳過。
#include<bits/stdc++.h> #define ll long long #define MAXNUM 1000000*4+10 using namespace std; struct node{ ll l,r,lef,rig; ll val,Max; }tree[210000]; ll a[110000],len,n,m; void build(ll l,ll r){ ll root=++len; tree[root].l=l;tree[root].r=r;tree[root].lef=tree[root].rig=-1; if(l==r)tree[root].val=tree[root].Max=a[l]; else{ ll mid=(l+r)/2; ll lef=tree[root].lef=len+1;build(l,mid); ll rig=tree[root].rig=len+1;build(mid+1,r); tree[root].val=tree[lef].val+tree[rig].val; tree[root].Max=max(tree[lef].Max,tree[rig].Max); } } void update(ll root,ll l,ll r){ if(tree[root].Max<2) return ; if(tree[root].l==tree[root].r){tree[root].val=sqrt(tree[root].val);tree[root].Max=tree[root].val;return ;} ll lef=tree[root].lef,rig=tree[root].rig,mid=(tree[root].l+tree[root].r)/2; if(r<=mid) update(lef,l,r); else if(mid<l) update(rig,l,r); else update(lef,l,mid),update(rig,mid+1,r); tree[root].val=tree[lef].val+tree[rig].val; tree[root].Max=max(tree[lef].Max,tree[rig].Max); } ll query(ll root,ll l,ll r){ if(tree[root].l>=l&&tree[root].r<=r) return tree[root].val; ll lef=tree[root].lef,rig=tree[root].rig,mid=(tree[root].l+tree[root].r)/2; if(r<=mid) return query(lef,l,r); else if(mid<l) return query(rig,l,r); else return query(lef,l,mid)+query(rig,mid+1,r); } int main(){ scanf("%lld",&n); for(ll i=1;i<=n;i++) scanf("%lld",&a[i]); build(1,n); scanf("%lld",&m); while(m--){ char s;cin>>s; if(s=='2'){ ll x,y;scanf("%lld%lld",&x,&y); update(1,x,y); }else{ ll x,y;scanf("%lld%lld",&x,&y); printf("%lld\n",query(1,x,y)); } } return 0; }
有長爲 \(n\) 的數列,不妨設爲 \(a_1,a_2,\cdots ,a_n\)。有以下三種操做形式:
線段樹瞎搞。乘法的優先級要高一些。
注意MOD
#include<bits/stdc++.h> #define N 10000000+10 #define ll long long using namespace std; ll n,m,a[N],add[N*4+10],mod,p,mul[N*4+10]; ll tree[N*4+10]; void pushup(ll id){ tree[id]=tree[id<<1]+tree[(id<<1)|1]; tree[id]%=mod; } void push_down(ll cur,ll l,ll r,ll mid){ if(mul[cur]==1&&add[cur]==0) return; mul[cur<<1]=mul[cur<<1]*mul[cur]%mod; add[cur<<1]=(add[cur<<1]*mul[cur]%mod+add[cur])%mod; tree[cur<<1]=(tree[cur<<1]*mul[cur]%mod+add[cur]*(ll)(mid-l+1)%mod)%mod; mul[cur<<1|1]=mul[cur<<1|1]*mul[cur]%mod; add[cur<<1|1]=(add[cur<<1|1]*mul[cur]%mod+add[cur])%mod; tree[cur<<1|1]=(tree[cur<<1|1]*mul[cur]%mod+add[cur]*(ll)(r-mid)%mod)%mod; mul[cur]=1; add[cur]=0; return; } void update(ll id,ll l,ll r,ll ql,ll qr,ll val){ if(ql<=l&&qr>=r){ add[id]+=val;add[id]%=mod; tree[id]=(tree[id]+(ll)(r-l+1)*val%mod)%mod; return ; } push_down(id,l,r,l+r>>1); ll mid=l+((r-l)>>1); if(ql<=mid) update(id<<1,l,mid,ql,qr,val); if(qr>=mid+1) update((id<<1)|1,mid+1,r,ql,qr,val); pushup(id); } void updatemul(ll cur,ll L,ll R,ll l,ll r,ll x){ if(L>=l&&R<=r){ mul[cur]=mul[cur]*(ll)x%mod; add[cur]=add[cur]*(ll)x%mod; tree[cur]=tree[cur]*(ll)x%mod; return; } ll mid=L+R>>1; push_down(cur,L,R,mid); if(l<=mid) updatemul(cur<<1,L,mid,l,r,x); if(r>mid) updatemul(cur<<1|1,mid+1,R,l,r,x); pushup(cur); } ll query(ll id,ll L,ll R,ll l,ll r){ if(L>=l&&R<=r) return tree[id]%mod; ll mid=L+R>>1; ll ans=0; push_down(id,L,R,mid); if(l<=mid) ans=(ans+query(id<<1,L,mid,l,r))%mod; if(r>mid) ans=(ans+query(id<<1|1,mid+1,R,l,r))%mod; pushup(id); return ans; } void build(ll L,ll R,ll x,ll y,ll cur){ mul[cur]=1;add[cur]=0;tree[cur]+=y; if(L==R) return; ll mid=L+R>>1; if(x>mid) build(mid+1,R,x,y,cur<<1|1); else build(L,mid,x,y,cur<<1); pushup(cur); } int main(){ scanf("%lld%lld",&n,&mod); for(ll i=1;i<=n;i++) scanf("%lld",&a[i]),build(1,n,i,a[i]%mod,1); scanf("%lld",&m); for(ll i=1;i<=m;i++){ ll type; scanf("%lld",&type); if(type==1){ ll x,y,k; scanf("%lld%lld%lld",&x,&y,&k); updatemul(1,1,n,x,y,k); } if(type==2){ ll x,y,k; scanf("%lld%lld%lld",&x,&y,&k); update(1,1,n,x,y,k); } if(type==3){ ll x,y; scanf("%lld%lld",&x,&y); ll temp=query(1,1,n,x,y); printf("%lld\n",temp%mod); } } return 0; }
求不定方程:
\[ \frac{1}{x}+\frac{1}{y}=\frac{1}{n!} \]
的正整數解 \((x,y)\) 的數目。
\[ \frac{1}{x}+\frac{1}{y}=\frac{1}{n!} \]
\[ \frac{y}{xy}+\frac{x}{xy}=\frac{1}{n!} \]
\[ \frac{x+y}{xy}=\frac{1}{n!} \]
\[ n!\times(x+y)=xy \]
\[ x+y=\frac{xy}{n!} \]
\[ (x-n!)*(y-n!)=(n!)^2 \]
#include<bits/stdc++.h> using namespace std; long long f[1000010],v[1000010],tot,ans[1000010],Ans=0; long long n; void prime(){ for(long long i=2;i<=1000000;i++){ if(!v[i]) v[i]=i,f[++tot]=i; for(long long j=1;j<=tot;j++){ if(f[j]>v[i]||f[j]>1000000/i) break; v[i*f[j]]=f[j]; } } } int main(){ scanf("%lld",&n); prime();long long tmp=n; memset(ans,0,sizeof(ans));Ans=1; for(int i=1;f[i]<=n&&i<=tot;i++){ long long tmp=0; for(long long j=f[i];j<=n;j*=f[i]){ tmp+=n/j; tmp%=1000000007; } Ans*=2*tmp+1; Ans%=1000000007; } printf("%lld\n",Ans); }
將 \(n\) 堆石子繞圓形操場排放,現要將石子有序地合併成一堆。規定每次只能選相鄰的兩堆合併成新的一堆,並將新的一堆的石子數記作該次合併的得分。
請編寫一個程序,讀入堆數 \(n\) 及每堆的石子數,並進行以下計算:
DP水過去。。。
設\(f[i][j]\)表示區間\([i,j]\)得分的最大值。
很容易能夠想到:
\[f[i][j]=max(f[i][k]+f[k+1][j]+dist(i,j)))\]
\[dist(i,j)=a[i]+a[i+1]+...+a[j-1]+a[j]\]
因此咱們設\(sum[i]=a[1]+a[2]+...+a[i-1]+a[i]\)
可得:
\[sum[i]=sum[i-1]+a[i]\]
那麼:
\[f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1])\]
可是,仔細讀題,發現是環。。。!
因此咱們將環轉換成鏈,即將\(a\)數組日後\(n\)個單位複製一遍。
與最大值差很少。改一個符號\(max------>min\)。
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cctype> #include<cerrno> #include<cfloat> #include<ciso646> #include<climits> #include<clocale> #include<cmath> #include<csetjmp> #include<csignal> #include<cstdarg> #include<cstddef> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #define E 200010 using namespace std; inline int read(){ int res=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } int n,f[210][210],a[210],sum[210],ans; int main(){ n=read(); for(int i=1;i<=n;i++) a[i]=read(),a[i+n]=a[i]; for(int i=1;i<=n*2;i++) sum[i]=sum[i-1]+a[i]; memset(f,63,sizeof(f)); for(int i=1;i<=n*2;i++) f[i][i]=0; for(int L=2;L<=n;L++){ for(int i=1;i<=n*2-L+1;i++){ int j=i+L-1; for(int k=i;k<j;k++){ f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]); } } } ans=2e9; for(int i=1;i<=n;i++){ ans=min(ans,f[i][i+n-1]); } write(ans);putchar('\n'); memset(f,0,sizeof(f)); for(int i=1;i<=n*2;i++) f[i][i]=0; for(int L=2;L<=n;L++){ for(int i=1;i<=n*2-L+1;i++){ int j=i+L-1; for(int k=i;k<j;k++){ f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]); } } } ans=0; for(int i=1;i<=n;i++){ ans=max(ans,f[i][i+n-1]); } write(ans);putchar('\n'); return 0; }
有\(n\)顆珠子,每一個珠子都有本身的標記,現將珠子串成項鍊(環),每相鄰的兩顆珠子能夠經過聚合釋放出能量=三顆珠子的標記之積,併合併成一顆更大的珠子,問聚合成一顆珠子後最大釋放的能量。
好比有一串項鍊:\(2-->3-->5-->10\),那麼把第一顆與第四顆珠子合併後產生的能量\(=2\times3\times10\)。那麼這一串項鍊最多可釋放:\((((4\bigotimes1)\bigotimes2)\bigotimes3)=(10\times2\times3)+10\times3\times5+10\times10\times5=710\)
設\(f[i][j]\)表示區間\([i,j]\)的珠子合併後產生能量的最大值。
\[f[i][j]=max(f[i][k]+f[k+1][j]+a[i]*a[j+1]*a[k+1])\]
也是把環展開就行了。。。233333333333.............
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cctype> #include<cerrno> #include<cfloat> #include<ciso646> #include<climits> #include<clocale> #include<cmath> #include<csetjmp> #include<csignal> #include<cstdarg> #include<cstddef> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #define E 200010 using namespace std; inline int read(){ int res=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } //queue<int> q; //set<int> s; //priority_queue<int> q1; //priority_queue<int,vector<int>,greater<int> > q2; //list<int> l; //stack<int> s; int n,f[210][210],a[210],sum[210],ans; int main(){ n=read(); for(int i=1;i<=n;i++) a[i]=read(),a[i+n]=a[i]; memset(f,0,sizeof(f)); for(int i=1;i<=n*2;i++) f[i][i]=0; for(int L=2;L<=n;L++){ for(int i=1;i<=n*2-L+1;i++){ int j=i+L-1; for(int k=i;k<=j-1;k++){ f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+a[i]*a[j+1]*a[k+1]); } } } ans=0; for(int i=1;i<=n;i++){ ans=max(ans,f[i][i+n-1]); } write(ans);putchar('\n'); return 0; }
給定一個具備 \(N\) 個頂點的凸多邊形,將頂點從 \(1\) 至 \(N\) 標號,每一個頂點的權值都是一個正整數。將這個凸多邊形劃分紅 \(N-2\) 個互不相交的三角形,試求這些三角形頂點的權值乘積和至少爲多少。
首先隨便搞一個多邊形:
而後給它順時針每一個頂點表上序號:
而後枚舉\(i,j\),要求:\(i+1<j\),而後給\(i,j\)連一條線,分割出來另外一個多邊形:多邊形23456
而後在\(i,j\)範圍內枚舉\(k\),使得多邊形23456又能夠分割。
分割成以下圖:
設\(f[i][j]\)表示把\(i,j\)的多邊形切割成三角形後的權值乘積之和的最小值。
可得:
\[f[i][j]=min\{f[i][k]+f[k][j]+a[i]*a[j]*a[k]\}(0<i<j<k\leq n)\]
初始化:
\[f[i][j]=inf(0<i\leq n,0<j\leq n)\]
\[f[i][i+1]=0(0<i<n)\]
時間複雜度:\(O(n^3)\)
輸出結果:\(f[1][n]\)
固然,這道題範圍特別大:對於 \(100\\%\) 的數據,有 \(N\le 50\),每一個點權值小於 \(10^9\)。三個數相乘最高可達\(10^{27}\),因此須要使用高精度。這裏使用了C++大數類,轉自代號4101
#include<bits/stdc++.h> using namespace std; const int maxn = 1000; struct bign{ int d[maxn], len; void clean() { while(len > 1 && !d[len-1]) len--; } bign() { memset(d, 0, sizeof(d)); len = 1; } bign(int num) { *this = num; } bign(char* num) { *this = num; } bign operator = (const char* num){ memset(d, 0, sizeof(d)); len = strlen(num); for(int i = 0; i < len; i++) d[i] = num[len-1-i] - '0'; clean(); return *this; } bign operator = (int num){ char s[20]; sprintf(s, "%d", num); *this = s; return *this; } bign operator + (const bign& b){ bign c = *this; int i; for (i = 0; i < b.len; i++){ c.d[i] += b.d[i]; if (c.d[i] > 9) c.d[i]%=10, c.d[i+1]++; } while (c.d[i] > 9) c.d[i++]%=10, c.d[i]++; c.len = max(len, b.len); if (c.d[i] && c.len <= i) c.len = i+1; return c; } bign operator - (const bign& b){ bign c = *this; int i; for (i = 0; i < b.len; i++){ c.d[i] -= b.d[i]; if (c.d[i] < 0) c.d[i]+=10, c.d[i+1]--; } while (c.d[i] < 0) c.d[i++]+=10, c.d[i]--; c.clean(); return c; } bign operator * (const bign& b)const{ int i, j; bign c; c.len = len + b.len; for(j = 0; j < b.len; j++) for(i = 0; i < len; i++) c.d[i+j] += d[i] * b.d[j]; for(i = 0; i < c.len-1; i++) c.d[i+1] += c.d[i]/10, c.d[i] %= 10; c.clean(); return c; } bign operator / (const bign& b){ int i, j; bign c = *this, a = 0; for (i = len - 1; i >= 0; i--) { a = a*10 + d[i]; for (j = 0; j < 10; j++) if (a < b*(j+1)) break; c.d[i] = j; a = a - b*j; } c.clean(); return c; } bign operator % (const bign& b){ int i, j; bign a = 0; for (i = len - 1; i >= 0; i--) { a = a*10 + d[i]; for (j = 0; j < 10; j++) if (a < b*(j+1)) break; a = a - b*j; } return a; } bign operator += (const bign& b){ *this = *this + b; return *this; } bool operator <(const bign& b) const{ if(len != b.len) return len < b.len; for(int i = len-1; i >= 0; i--) if(d[i] != b.d[i]) return d[i] < b.d[i]; return false; } bool operator >(const bign& b) const{return b < *this;} bool operator<=(const bign& b) const{return !(b < *this);} bool operator>=(const bign& b) const{return !(*this < b);} bool operator!=(const bign& b) const{return b < *this || *this < b;} bool operator==(const bign& b) const{return !(b < *this) && !(b > *this);} string str() const{ char s[maxn]={}; for(int i = 0; i < len; i++) s[len-1-i] = d[i]+'0'; return s; } }; istream& operator >> (istream& in, bign& x){ string s; in >> s; x = s.c_str(); return in; } ostream& operator << (ostream& out, const bign& x){ out << x.str(); return out; } #define ll bign ll f[55][55],a[55]; int n; int main(){ cin>>n; for(int i=1;i<=n;i+=1) cin>>a[i]; memset(f,63,sizeof(f)); for(int i=1;i<=n;i++) f[i][i+1]=0; for(int L=2;L<=n-1;L++){ for(int i=1;i<=n-L;i++){ int j=i+L; for(int k=i+1;k<=j-1;k++){ f[i][j]=min(f[i][k]+f[k][j]+a[i]*a[j]*a[k],f[i][j]); } } } cout<<f[1][n];putchar('\n'); return 0; } //f[i][j]=min{f[i][k]+f[k][j]+a[i]*a[j]*a[k]}(0<i<k<j<=n) //f[i][j]=inf //f[i][i+1]=0; //end:f[1][n] //Time:O(n^3)
有一棵二叉蘋果樹,若是數字有分叉,必定是分兩叉,即沒有隻有一個兒子的節點。這棵樹共 \(N\) 個節點,標號 \(1\) 至 \(N\),樹根編號必定爲 \(1\)。
咱們用一根樹枝兩端鏈接的節點編號描述一根樹枝的位置。一棵有四根樹枝的蘋果樹,由於樹枝太多了,須要剪枝。可是一些樹枝上長有蘋果,給定須要保留的樹枝數量,求最多能留住多少蘋果。
設\(f[i][j]\)表示以i爲根節點,保留j個節點的最大蘋果數量
\[f[i][j]=max{f[l[i]][k]+f[r[i]][j-k-1]+a[i]}(0<=k<=j-1)\]
\[f[i][j]=0(0<i<=n,0<=j<=Q+1)\]
\[f[i][j]=a[i](j!=0,l[i]==0,r[i]==0)\]
\[Answer:f[1][Q+1]\]
#include<bits/stdc++.h> #define ll long long using namespace std; inline ll read(){ char ch=getchar();ll res=0,f=1; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*f; } inline void write(ll x){ if(x<0) putchar('-'),x=-x; if(x<10) putchar(x+'0'); else{ write(x/10); putchar(x%10+'0'); } } ll n,Q,f[110][110],a[110],l[110],r[110],mp[110][110]; void MakeTree(int x){ for(int i=1;i<=n;i++){ if(mp[x][i]!=-1){ l[x]=i;a[i]=mp[x][i]; mp[x][i]=mp[i][x]=-1; MakeTree(i); break; } }//Make Left Son for(int i=1;i<=n;i++){ if(mp[x][i]!=-1){ r[x]=i;a[i]=mp[x][i]; mp[x][i]=mp[i][x]=-1; MakeTree(i); break; } }//Make Right Son } int DP(int x,int j){ if(j==0){f[x][j]=0;return 0;} if((!l[x])&&(!r[x])){f[x][j]=a[x];return a[x];} if(f[x][j]>0) return f[x][j]; for(int k=0;k<j;k++) f[x][j]=max(f[x][j],DP(l[x],k)+DP(r[x],j-k-1)+a[x]); return f[x][j]; } int main(){ n=read();Q=read();Q++; memset(mp,-1,sizeof(mp)); for(int i=1;i<=n-1;i++){ int x=read(),y=read(),z=read(); mp[y][x]=mp[x][y]=z; } MakeTree(1); write(DP(1,Q));putchar('\n'); /* cout<<"-----------------------------------"<<endl; for(int i=1;i<=n;i++){ cout<<"Node "<<i<<":\n"; cout<<"Left Son:"<<l[i]<<" Right Son:"<<r[i]<<endl; cout<<"Val:"<<a[i]<<endl; cout<<"DP :\n"; for(int j=0;j<=Q;j++){ cout<<"Has "<<j<<":"<<f[i][j]<<endl; } cout<<endl; } */ return 0; } //設f[i][j]表示以i爲根節點,保留j個節點的最大蘋果數量 //f[i][j]=max{f[l[i]][k]+f[r[i]][j-k-1]+a[i]}(0<=k<=j-1) //f[i][j]=0(0<i<=n,0<=j<=Q+1) //f[i][j]=a[i](j!=0&&l[i]==0&&r[i]==0) //Answer:f[1][Q+1] /* Sample Input: 5 2 1 3 1 1 4 10 2 3 20 3 5 20 Sample Output: 21 */
有不少課程,但部分課程有先修課。學生不可能學完大學開設的全部課程,所以必須在入學時選定本身要學的課程。每一個學生可選課程的總數是給定的。請找出一種選課方案使得你能獲得的學分最多,並知足先修課優先的原則。假定課程間不存在時間上的衝突。
瞎搞樹形DP。
發現這是揹包。
仍是分組揹包。(^▽^)
因而就愉快地解決了。
設\(f[x][t]\)表示以x爲根節點的子樹中選t門課可以得到的最高學分。(因此說是揹包問題嘛)
\[Answer:f[0][m]\]
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cstring> #include<cmath> #define ll long long #define eps 1e-4 using namespace std; inline int read(){ int ret=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();} while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar(); return ret*f; } inline void write(int zx){ if(zx<0){zx=-zx;putchar('-');} if(zx<10) putchar(zx+'0'); else{ write(zx/10); putchar(zx%10+'0'); } } int n,m,fir[310],nxt[310]; int s[310],w[310],f[310][310]; int DP(int x){ if(fir[x]==-1) return 0; int sum=0; for(int i=fir[x];i!=-1;i=nxt[i]){ int tmp=DP(i); sum+=tmp+1; for(int j=sum;j>=0;j--) for(int k=0;k<=tmp;k++) if(j-k-1>=0) f[x][j]=max(f[x][j],f[x][j-k-1]+f[i][k]); } return sum; } int main(){ n=read();m=read(); memset(fir,-1,sizeof(fir)); for(int i=1;i<=n;i++){ s[i]=read();w[i]=read(); nxt[i]=fir[s[i]]; fir[s[i]]=i; } for(int i=1;i<=n;i++) f[i][0]=w[i]; f[0][0]=0; DP(0); write(f[0][m]); putchar('\n'); return 0; }
若是一個數 \(x\) 的約數和 \(y\) (不包括他自己)比他自己小,那麼 \(x\) 能夠變成 \(y\),\(y\) 也能夠變成 \(x\)。例如 \(4\) 能夠變爲 \(3\),\(1\) 能夠變爲 \(7\)。限定全部數字變換在不超過 \(n\) 的正整數範圍內進行,求不斷進行數字變換且不出現重複數字的最多變換步數。
求樹的最長鏈
設\(d1[i]\)爲以\(i\)爲根的子樹中,i到葉子節點距離最大值
設\(d2[i]\)爲以\(i\)爲根的子樹中,i的葉子節點距離次大值(除了最大值所在的子樹)
若j爲i的兒子,那麼:
最後掃描全部節點,最長鏈=max{d1[i]+d2[i]}
#include<algorithm> #include<bitset> #include<complex> #include<deque> #include<exception> #include<fstream> #include<functional> #include<iomanip> #include<ios> #include<iosfwd> #include<iostream> #include<istream> #include<iterator> #include<limits> #include<list> #include<locale> #include<map> #include<memory> #include<new> #include<numeric> #include<ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf> #include<string> #include<typeinfo> #include<utility> #include<valarray> #include<vector> #include<cstring> #include<cmath> #define ll long long #define eps 1e-4 using namespace std; //priority_queue<int,vector<int>,greater<int> > q1; //priority_queue<int> q2; //set<int> s; //list<int> l; //map<int> mp; inline int read(){ int ret=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();} while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar(); return ret*f; } inline void write(int zx){ if(zx<0){zx=-zx;putchar('-');} if(zx<10) putchar(zx+'0'); else{ write(zx/10); putchar(zx%10+'0'); } } int sum[500001],n,d1[500001],d2[500001],ans; void Pri(){ for(int i=1;i<=n;i++){ for(int j=2;j<=n/i;j++){ if(i*j>n) break; sum[i*j]+=i; } } } void dp(){ for(int i=n;i>=1;i--){ if(sum[i]<i){ if(d1[i]+1>d1[sum[i]]){ d2[sum[i]]=d1[sum[i]]; d1[sum[i]]=d1[i]+1; }else if(d1[i]+1>d2[sum[i]]) d2[sum[i]]=d1[i]+1; } } } int main(){ n=read(); Pri(); dp(); for(int i=1;i<=n;i++) ans=max(ans,d1[i]+d2[i]); write(ans);putchar('\n'); return 0; }