二分答案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)\)