二分答案c++
應該有反例,就是說,答案應該不是單調的算法
可是不會寫其餘的算法了啊。。。數組
我TM。。。函數
第二個紅框圈出來的部分應該是學習
if(x1+x1!=s)
寫錯了,就沒了\(18\)分。。優化
寫了個\(n^4\)的暴力spa
最後發現題目中的矩形的四個頂點不必定是給定的頂點。。3d
那就GG了code
/* * 二分答案。。 * 複雜度O(20(N+NlogN+M))的,感受很懸 * 排序應該能夠優化掉,可是不太會哎。 */ #include <cstdio> #include <algorithm> inline int read() { int n=0,w=1;register char c=getchar(); while(c<'0' || c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0' && c<='9')n=n*10+c-'0',c=getchar(); return n*w; } const int N=1e6+1; int n,m; struct Seg{ int b,k; }seg[N]; long long S,emp[N]; inline bool judge(long long x) { for(int i=1;i<=n;++i) emp[i]=seg[i].k*x+seg[i].b; std::sort(emp+1,emp+1+n); /* for(int i=1;i<=n;++i) printf("%lld ",emp[i]); puts(""); */ long long res=0; for(int i=0;i<m;++i) { if(emp[n-i]<0)break; res+=emp[n-i]; } // printf("%lld\n",res); return res>=S; } int main() { freopen("merchant.in","r",stdin); freopen("merchant.out","w",stdout); n=read(),m=read(); scanf("%lld",&S); // printf("%d %d %lld\n",n,m,S); for(int i=1;i<=n;++i) { seg[i].k=read(),seg[i].b=read(); // printf("%d %d\n",seg[i].k,seg[i].b); } int l=0,r=1e9,mid; while(l<=r) { mid=l+r>>1; if(judge(mid)) r=mid-1; else l=mid+1; } printf("%d",l); fclose(stdin),fclose(stdout); return 0; }
/* * 題目描述什麼鬼啊。。。徹底看不懂 * * emmmm * 高斯消元麼。。。 */ #include <cstdio> #include <algorithm> inline int read() { int n=0,w=1;register char c=getchar(); while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9')n=n*10+c-'0',c=getchar(); return n*w; } const int N=1e6+1; int n,q,fa[N],w[N]; /* const double eps=1e-8; double a[N][N]; int sign(double x) {//判斷一個數是正數、負數仍是0 if(fabs(x)<=eps)return 0;//fabs是對浮點數取絕對值 if(x>0)return 1; return -1; } inline void GG(int x) { if(a[x][n+1]) puts("none"); else puts("inf"); } inline void solve() { for(int i=1;i<=n;++i) a[i][n+1]=b[i];//獲得擴展矩陣 for(int i=1;i<=n;++i) { int p=i; for(int j=i+1;j<=n;++j) if(fabs(a[j][i]>fabs(a[p][i]))) p=j; for(int j=1;j<=n+1;++j) swap(a[p][j],a[i][j]); if(sign(a[i][i])==0) GG(i); for(int j=i+1;j<=n;++j) { double ratio=a[j][i]/a[i][i];//計算是多少倍 for(int k=1;k<=n+1;++k) a[j][k]=a[j][k]-ratio*a[i][k]; } for(int i=n;i>0;--i) { for(int j=i+1;j<=n;++j) a[i][n+1]=a[i][n+1]-x[j]*a[i][j]; x[i]=a[i][n+1]/a[i][i]; } } int main() { freopen("equation.in","r",stdin); freopen("equation.out","w",stdout); n=read(),q=read(); for(int i=2;i<=n;++i) fa[i]=read(),w[i]=read(); int type,u,v,s; while(q--) { type=read(),u=read(),v=read(); if(type==1) { s=read(); solve(); } else { w[u]=v; a[u][fa[u]]=v; } } fclose(stdin);fclose(stdout); return 0; } 日。。 寫掛了 */ int main() { freopen("equation.in","r",stdin); freopen("equation.out","w",stdout); n=read(),q=read(); for(int i=2;i<=n;++i) fa[i]=read(),w[i]=read(); int type,u,v,s; int x2,x1; if(n==2) { while(q--) { type=read(),u=read(),v=read(); if(type==1) { s=read(); if(u==v && v==2) { x2=s/2; if(x2+x2!=s) puts("none"); else printf("%d\n",w[2]-x2); } else if(u==v && v==1) { x1=s/2; if(x2+x2!=s) puts("none"); else printf("%d\n",x1); } else { if(s==w[2]) puts("inf"); else puts("none"); } } else w[u]=v; } } else { while(q--) { srand(19260817); while(q--) { int x=rand(); if(x%3==1) puts("none"); else if(x%3==2) puts("inf"); else printf("%d\n",x); } } } fclose(stdin);fclose(stdout); return 0; }
#include <cstdio> #include <map> const int N=2501,mod=1e9+7; std::map<int,bool> mp1,mp2; int n,t1,t2,lx,ly,rx,ry; int ans,x[N],y[N]; inline int read() { int n=0,w=1;register char c=getchar(); while(c<'0' || c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0' && c<='9')n=n*10+c-'0',c=getchar(); return n*w; } inline int min(int x,int y) {return x<y?x:y;} inline int max(int x,int y) {return x>y?x:y;} int main() { freopen("rectangle.in","r",stdin); freopen("rectangle.out","w",stdout); n=read(); for(int i=1;i<=n;++i) x[i]=read(),y[i]=read(); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) for(int q=1;q<=n;++q) for(int p=1;p<=n;++p) { if(i==j&&j==q&&q==p)continue; lx=min(min(x[i],x[j]),min(x[q],x[p])); ly=min(min(y[i],y[j]),min(y[q],y[p])); rx=max(max(x[i],x[j]),max(x[q],x[p])); ry=max(max(y[i],y[j]),max(y[q],y[p])); t1=(lx*ry+ly*rx); t2=(lx*rx+ly*ry); if(mp1[t1]==0&&mp2[t2]==0) { ans=(ans+(rx-lx)*(ry-ly))%mod; mp1[t1]=mp2[t2]=1; } } printf("%d",ans); fclose(stdin);fclose(stdout); return 0; }
選擇任意一個集合,獲得的收益和均可以表示爲一個一次函數的形式。blog
咱們只關心這些一次函數的最大值,能夠發現這個最大值必定是先降後增、單調遞增或者單調遞減。
所以咱們只須要\(check\)一下\(0\)時刻是否符合條件,若是不符合則進行二分。 注意\(check\)的時候咱們只須要找出最大的\(m\)個便可,所以能夠\(O(n)\)地作,具體作法是快排的過程當中只遞歸一邊,或者直接用\(STL\)的\(nth_element()\)便可
#include <bits/stdc++.h> #define For(i, j, k) for (int i = j; i <= k; i++) using namespace std; const int N = 1e6 + 10; typedef long long LL; int n, m; LL S; int k[N], b[N]; LL val[N]; bool check(int x) { For(i, 1, n) val[i] = 1ll * k[i] * x + b[i]; nth_element(val + 1, val + m, val + n + 1, greater<LL>()); LL sum = 0; For(i, 1, m) if (val[i] > 0 && (sum += val[i]) >= S) return true; return sum >= S; } int main() { scanf("%d%d%lld", &n, &m, &S); For(i, 1, n) scanf("%d%d", &k[i], &b[i]); if (check(0)) { puts("0"); return 0; } int L = 1, R = 1e9; while (L < R) { int mid = (L + R) / 2; if (check(mid)) R = mid; else L = mid + 1; } printf("%d\n", L); return 0; }
每一個變量均可以表示成\(x_i=k+x_1\)或者\(x_i=k−x_1\)的形式,表示爲這個形式以後就能夠方便地回答詢問了。
對於詢問\(1\),只須要將表示\(u\)和\(v\)的式子加起來,這時會出現兩種狀況:要麼會獲得\(x_u+x_v=t\)的形式,此時只須要判斷是否有\(s=t\);要麼會獲得\(x_u+x_v=t+2x_1\)或\(x_u+x_v=t−2x_1\),此時能夠解出\(x_1\),注意判斷解是不是整數便可。
對於修改操做,其實是修改一個子樹內的變量的\(k\),這裏能夠將深度爲奇數和偶數的點分開考慮,不難發現就是區間加減。因爲只須要單點詢問,用一個樹狀數組維護便可
\(O((n+q)\log n)\)
#include <bits/stdc++.h> #define getchar getchar_unlocked #define For(i, j, k) for (int i = j; i <= k; i++) using namespace std; int Read() { char c = getchar(); int x = 0; int sig = 1; while (c < '0' || c > '9') { if (c == '-') sig = -1; c = getchar(); } while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * sig; } const int N = 1e6 + 10; int n, q; struct Binary_Indexed_Tree { int c[N]; inline int lowbit(int x) { return x & (-x); } void add(int x, int w) { while (x <= n) { c[x] += w; x += lowbit(x); } } int sum(int x) { int ret = 0; while (x) { ret += c[x]; x -= lowbit(x); } return ret; } }T; int dfn[N], rdfn[N], dep[N]; int fa[N], w[N]; vector<int> G[N]; void DFS_init(int o) { static int clk = 0; dfn[o] = ++clk; for (int v : G[o]) dep[v] = dep[o] ^ 1, DFS_init(v); rdfn[o] = clk; } int main() { n = Read(), q = Read(); For(i, 2, n) fa[i] = Read(), w[i] = Read(), G[fa[i]].push_back(i); DFS_init(1); For(i, 2, n) if (!dep[i]) w[i] = -w[i]; For(i, 2, n) T.add(dfn[i], w[i]), T.add(rdfn[i] + 1, -w[i]); while (q--) { int op = Read(); if (op == 1) { int u = Read(), v = Read(), s = Read(); int x = T.sum(dfn[u]), y = T.sum(dfn[v]); if (dep[u] && dep[v]) { long long rt = 1ll * x + y - s; if (rt % 2) puts("none"); else printf("%lld\n", rt / 2); } else if (!dep[u] && !dep[v]) { long long rt = 1ll * x + y + s; if (rt % 2) puts("none"); else printf("%lld\n", rt / 2); } else { if (dep[v]) swap(u, v), swap(x, y); if (x - y == s) puts("inf"); else puts("none"); } } else { int u = Read(), nw = Read(); if (!dep[u]) nw = -nw; T.add(dfn[u], nw - w[u]), T.add(rdfn[u] + 1, w[u] - nw); w[u] = nw; } } return 0; }
#include <bits/stdc++.h> #define For(i, j, k) for (int i = j; i <= k; i++) #define Forr(i, j, k) for (int i = j; i >= k; i--) using namespace std; const int N = 2510; const int Mod = 1e9 + 7; int n, m = 2500; struct Binary_Indexed_Tree { int c[N]; void init() { For(i, 1, m) c[i] = 0; } int lowbit(int x) { return x & (-x); } void add(int x, int w) { for (; x <= m; x += lowbit(x)) c[x] += w; } int sum(int x) { int ret = 0; for (; x; x -= lowbit(x)) ret += c[x]; return ret; } }T, S; int pos[N][N]; int c[N]; bool vis[N]; void upd(int x) { if (vis[x]) return; vis[x] = true; T.add(x, 1), S.add(x, x); } int main() { scanf("%d", &n); For(i, 1, n) { int x, y; scanf("%d%d", &x, &y); pos[x][++c[x]] = y; } For(i, 1, m) sort(pos[i] + 1, pos[i] + c[i] + 1), pos[i][c[i] + 1] = m + 1; int ans = 0; For(i, 1, m) if (c[i]) { T.init(), S.init(); For(j, 1, m) vis[j] = false; For(j, 1, c[i]) upd(pos[i][j]); Forr(j, i - 1, 1) if (c[j]) { int pa = 1, pb = 1, cur = max(pos[i][1], pos[j][1]); For(k, 1, c[j]) upd(pos[j][k]); while (pos[i][pa + 1] <= cur) ++pa; while (pos[j][pb + 1] <= cur) ++pb; while (pa <= c[i] && pb <= c[j]) { int nxt = min(pos[i][pa + 1], pos[j][pb + 1]), L = min(pos[i][pa], pos[j][pb]); ans = (ans + (1ll * (S.sum(nxt - 1) - S.sum(cur - 1)) * T.sum(L) - 1ll * (T.sum(nxt - 1) - T.sum(cur - 1)) * S.sum(L)) * (i - j)) % Mod; cur = nxt; if (pos[i][pa + 1] <= cur) ++pa; if (pos[j][pb + 1] <= cur) ++pb; } } } printf("%d\n", ans); return 0; }
一個長度爲\(n\)的序列\(A\),咱們稱一個元素是好的,當且僅當它嚴格大於相鄰的元素。你能夠進行若干次操做,每次將一個元素減少\(1\)
對於每一個\(k\in [1,\lceil\frac{n}{2}\rceil]\)求至少要進行多少次操做使得序列中至少有\(k\)個好的元素
\(n\le 5000,A_i\le 10^5\)
解:
稍做觀察發現,若是最終方案中一個位置是好的,那咱們必定不會對它作操做;若是不是,它最終的值是\(A_{i-1}-1,A_i,A_{i+1}-1\)中的一個
令\(dp[i][j][0]\)表示前\(i\)個元素有\(j\)個是好的,且已經欽定\(A_i\)是好的,此
時對前\(i\)個元素至少要進行的操做次數。轉移到\(i+1\)時須要確保操做後\(A_{i+1}\lt A_i\)
相似地,\(dp[i][j][1/2/3]\)表示\(A_i\)不是好的時的三種狀況
\(O(n^2)\)
一個長度爲\(n\)的序列\(A\),定義一個1到n的排列p是合法的,當且僅當\(\forall i\in[1,n-1].A_{p_i}\times A_{p_{i+1}}\)不是徹底平方數
求有多少合法的排列,對\(1e9+7\)取模
\(n\le 300,A_i\le 10^9\)
解:
對於每一個元素去掉它的平方質因子,問題轉化爲有多少排列\(p\)知足\(\forall i\in[1,n-1],A_{p_i}\ne A_{p_{i+1}}\),即相鄰元素不一樣
先統計有多少種不一樣的元素,以及每種元素的個數。考慮每次將值相同的全部元素加入排列後的序列
設\(dp[i][j]\)表示已經將前\(i\)種元素加入序列,有\(j\)對相鄰位置相同的方案數。轉移時枚舉將第\(i+1\)種元素加入後會將多少對原來不合法的相鄰位置拆開,以及會新增多少不合法的相鄰位置便可。
總元素個數\(O(n)\),所以複雜度最壞\(O(n^3)\)
有一個長度爲\(n\)的序列\(A\)和常數\(L,P\),你須要將它分紅若干段,每一段的代價爲\(|(\sum A_i)-L|^P\),求最小代價的劃分方案
\(n\le 10^5,1\le P\le 10\)
解:
\[ dp[j]=\min_{i=0}^{j-1}|sum_j-sum_i-L|^P+dp[i] \]
這個方程具備決策單調性,即\(\forall u\lt v\lt i\lt j\),若在\(i\)處決策\(v\)優於決策\(u\),則在\(j\)處必有\(v\)優於決策\(u\)
用一個棧維護每一個決策更新的區間,新加入一個決策時能夠二分獲得它的區間
\(O(n\log n)\)
證實:
本題的證實須要討論絕對值符號,先考慮裏面的值爲正的狀況,其他的狀況相似。
定義\(f_i(x)=dp[i]+(sum_x-sum_i-L)^P\),只需證實\(g(x)=f_u(x)-f_v(x),u\lt v\lt x\)單調增
也就是隨着\(x\)增大決策\(u\)相較於決策\(v\)愈來愈不優
\[ g(x)=(sum_x-sum_u)^P-(sum_x-sum_v)^P+dp[u]-dp[v]\\ g'(x)=P(sum_x-sum_u)^{P-1}-P(sum_x-sum_v)^{P-1}\\ g'(x)\ge 0 \]
一張\(n\)個點\(m\)條邊的帶權有向圖,每條邊的長度都爲\(1\)。求一條最長的路徑,知足邊權嚴格遞增,且路徑上邊的順序與輸入中這些邊的相對順序相同。
\(n,m\le 10^5\)
解:
按輸入順序考慮每一條邊。設\(dp[i][j]\)表示路徑到了節點\(i\),上一條邊的權值\(j\)時的最長長度。
顯然有用的狀態是\(O(m)\)的。對每一個點維護一個\(set\)來存這些狀態以及它們的\(dp\)值,並保證\(dp\)值是隨\(j\)遞增的。這樣加入一條邊\((u,v)\)時,只須要在節點\(u\)的\(set\)上二分就能夠進行轉移了。同時還須要維護\(v\)的\(set\)。
\(O(n+m\log m)\)
有一棵\(n\)個點的帶權二叉樹(不知道樹的形態),給出對這棵二叉樹進行中序遍歷獲得的權值序列,判斷是否存在與之相符的一棵二叉樹,樹上每對相鄰節點權值的\(gcd\)大於\(1\)
\(n\le 700,w_i\le 10^9\)
解
對於二叉樹的一棵子樹,其中序遍歷是一段連續的區間。一個想法(跟昨天的題目很像)是設\(dp[l][r][i]\)表示是否能將區間\([l,r]\)建成一棵以\(i\)爲根的合法二叉樹,轉移枚舉兩邊子樹的根,但這樣的複雜度是\(O(n^5)\)
注意到對於區間\([l,r]\)構成的二叉樹,除非\(l=1,r=n\),不然它必定是\(r+1\)的左子樹,或者\(l-1\)的右子樹。所以咱們只關心根節點與\(l-1\)和\(r+1\)的權值的\(gcd\)是否爲\(1\),而不須要知道根是哪一個節點。
因而狀態數變爲\(O(n^2)\),轉移仍然枚舉根便可,\(O(n^3)\)