T1
排序后二分
#include <algorithm> #include <cstdio> #include <cctype> #define N 200100 using namespace std; inline void read(int &x) { bool f=0;register char ch=getchar(); for(x=0;!isdigit(ch);ch=getchar()) if(ch=='-') f=1; for(;isdigit(ch);x=x*10+ch-'0',ch=getchar()); x=f?-x:x; } int n,m,X[N],Y[N]; double B[N],K[N]; bool check(double x1,double y1,int mid) { if(K[mid]*x1+B[mid]>y1) return 0; return 1; } int main() { freopen("geometry.in","r",stdin); freopen("geometry.out","w",stdout); read(n); for(int i=1;i<=n;i++) read(X[i]); for(int i=1;i<=n;i++) read(Y[i]); sort(X+1,X+n+1); sort(Y+1,Y+n+1); for(int i=1;i<=n;i++) { B[i]=(double)Y[i]; K[i]=-(double)Y[i]/(double)X[i]; } read(m); for(int i=1,x,y;i<=m;i++) { read(x);read(y); int l=1,r=n,ans=0; for(int mid;l<=r;) { mid=(l+r)>>1; if(check(x,y,mid)) ans=mid,l=mid+1; else r=mid-1; } printf("%d ",ans); } fclose(stdin); fclose(stdout); return 0; }
T2
差分约束做法
记录前缀和S[i],i>=8时首先要满足条件 s[i]-s[i-8]>=a[i]
0<=s[i]-s[i-1]<=b[i]
当i<8时有s[23]-s[16+i]+s[i]>=a[i]
因为第三个式子不满足差分约束形式,可以看出s[23]有单调性,可以二分…所以可以二分答案当常量处理
Spfa负环则无解
#include<cstring> #include<cstdio> int T,a[24],b[24],t[24],ans; int main() { freopen("cashier.in","r",stdin); freopen("cashier.out","w",stdout); scanf("%d",&T); while(T--) { memset(t,0,sizeof(t)); for(int i=0;i<24;i++) scanf("%d",&a[i]); for(int i=0;i<24;i++) scanf("%d",&b[i]); ans=-1; for(int i=0;i<24;i++) { if(a[i]>t[i]) { int j=i; while(a[i]>t[i]) { if(j+7<i) break; if(j==-1) break; if(b[j]+t[i]>=a[i]) { int res=a[i]-t[i]; b[j]=b[j]-res; if(j<=16) {for(int k=j;k<=j+7;k++) t[k]+=res;} else {for(int num=1,k=j;num<=8;++num) t[k]+=res,k=(k+1)%24;} ans+=res; break; } else { int res=b[j]; b[j]=0; if(j<=16) {for(int k=j;k<=j+7;k++) t[k]+=res;} else {for(int num=1,k=j;num<=8;++num) t[k]+=res,k=(k+1)%24;} ans+=res; j--; } } } } if(ans==-1||ans>1000) printf("%d ",ans); else printf("%d ",ans+1); } fclose(stdin); fclose(stdout); return 0; }
#include <cstdio> #include <cstdlib> #include <queue> #define N 33 using namespace std; struct edge { int t, n, l; }e[N * N]; int h[N],tote; void adde(int u, int v, int l) { e[++tote].t = v; e[tote].l = l; e[tote].n = h[u]; h[u] = tote; return ; } int d[N]; bool inq[N]; bool spfa() { queue<int> Q; for (int i = 0; i <= 24; i++) d[i] = -1e9, inq[i] = false; d[0] = 0; inq[0] = true; Q.push(0); while (!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = false; if (d[u] > 1000) return false; for (int i = h[u]; i; i = e[i].n) { int v = e[i].t, l = e[i].l; if (d[v] < d[u] + l) { d[v] = d[u] + l; if (!inq[v]) { inq[v] = true; Q.push(v); } } } } return true; } int a[30], b[30]; bool solve(int ans) { for (int i = 0; i <= 24; i++) h[i] = 0; tote = 0; for (int i = 9; i <= 24; i++) adde(i - 8, i, a[i]); for (int i = 1; i <= 8; i++) adde(i + 16, i, a[i] - ans); for (int i = 1; i <= 24; i++) adde(i - 1, i, 0); for (int i = 1; i <= 24; i++) adde(i, i - 1, -b[i]); adde(0, 24, ans); adde(24, 0, -ans); return spfa(); } int main(int argc, char ** argv) { freopen("cashier.in", "r", stdin); freopen("cashier.out", "w", stdout); int test; scanf("%d", &test); for (int i = 1; i <= test; i++) { for (int i = 1; i <= 24; i++) scanf("%d", &a[i]); for (int i = 1; i <= 24; i++) scanf("%d", &b[i]); int ans = 0; while (true) { if (++ans > 1000) { ans = -1; break; } if (solve(ans)) break; } printf("%d ", ans); } fclose(stdin); fclose(stdout); return 0; }
T3
线段树
部分分可以dp f[i][j]表示前i个数选了j个的答案
f[i][j]=f[i-1][j]+f[i-1][j-1]*a[i] (i选不选)
k比较小,所以线段树每个节点维护一个区间答案记为f[i]
考虑一段区间i,左边取j个右边就取i-j个 答案是每个方案的左边乘右边的和。
就是i左儿子f[j]和右边的f[i-j] 所以f[i]=Σ(j=0~i) lc f[j]*rc f[i-j]
考虑取反操作,i是奇数就取反,偶数无影响(因为是相乘)
考虑区间加, 开始f[i] 是 a1*a2……an 后来是(a1+c)*(a2+c)……(an+c)
考虑类似二项式定理,当上述a1~an n个方案如果取了j个了,分别为al1,al2……alj
那考虑最后答案,如果已经选了j个方案是(al1+c)(al2+c)……(alj+c)再还能选i-j个 最后答案是C(len-i,i-j)*f[j]*c^(i-j)
复杂度 O(k^2*nlogn)
#include <algorithm> #include <cstdio> #include <cctype> #define Mod 1000000007 typedef long long LL; #define BUF 12312312 LL n,m,ans,z,a[50005]; char Buf[BUF],*buf=Buf; inline void read(LL &x) { bool f=0; for(x=0;!isdigit(*buf);++buf) if(*buf=='-') f=1; for(;isdigit(*buf);x=x*10+*buf-'0',++buf); x=f?(-x):x; } void dfs(LL l,LL r,LL num,LL sc) { if(num==z) { ans=(ans+sc+Mod)%Mod; return; } for(int i=l;i<=r;++i) dfs(i+1,r,num+1,(sc*a[i]+Mod)%Mod); } int main(int argc,char *argv[]) { freopen("game.in","r",stdin); freopen("game.out","w",stdout); fread(buf,1,BUF,stdin); read(n),read(m); if(n<=100||m<=100) { for(int i=1;i<=n;++i) read(a[i]); for(LL opt,x,y;m--;) { read(opt),read(x);read(y); if(opt==2) {for(int i=x;i<=y;++i) a[i]=-a[i];} if(opt==1) {read(z);for(int i=x;i<=y;++i) a[i]=(a[i]+z+Mod)%Mod;} if(opt==3) { read(z); ans=0;dfs(x,y,0,1); printf("%I64d ",(ans+Mod)%Mod); } } } else { puts("hello ladies and gentlemen"); puts("i'm MC bytlxmdsyl"); puts("有一本书名叫天方夜谭"); puts("很奇妙又好看"); puts("叙述的是阿拉伯的故事"); puts("到处都在流传"); puts("由阿拉丁神灯"); puts("有辛巴达航海"); puts("one two three and four"); puts("come on yo let's go"); puts("这里有个神奇的故事"); puts("一个人 一个人"); puts("一个人的命运会改变"); puts("阿里 阿里巴巴"); puts("阿里巴巴是个快乐的青年"); puts("阿里 阿里巴巴"); puts("阿里巴巴是个快乐的青年"); puts("#芝麻开门#"); } fclose(stdin); fclose(stdout); return 0; }
#include <cstdio> #include <cstdlib> #define MOD 1000000007 #define N 100005 typedef long long LL; using namespace std; struct Node { LL f[11]; }node[N * 4]; LL a[N], lazy1[N * 4]; bool lazy2[N * 4]; LL C[N][11]; Node merge(Node lc, Node rc) { Node o; o.f[0] = 1; for (int i = 1; i <= 10; i++) { o.f[i] = 0; for (int j = 0; j <= i; j++) o.f[i] = (o.f[i] + lc.f[j] * rc.f[i - j] % MOD) % MOD; } return o; } void build(int o, int l, int r) { if (l == r) { for (int i = 0; i <= 10; i++) node[o].f[i] = 0; node[o].f[0] = 1; node[o].f[1] = (a[l] % MOD + MOD) % MOD; return ; } int mid = (l + r) >> 1; build(o * 2, l, mid); build(o * 2 + 1, mid + 1, r); node[o] = merge(node[o * 2], node[o * 2 + 1]); return ; } void update1(int o, int l, int r, int c) { int len = r - l + 1; LL ff[11]; for (int i = 0; i <= 10; i++) ff[i] = node[o].f[i]; for (int i = 1; i <= 10; i++) { node[o].f[i] = 0; LL t = 1; for (int j = 0; j <= i; j++) { LL tmp = ff[i - j] * C[len - (i - j)][j] % MOD * t % MOD; node[o].f[i] = (node[o].f[i] + tmp) % MOD; t = t * c % MOD; } } return ; } void push_down(int o, int l, int r) { int mid = (l + r) >> 1; if (lazy1[o]) { if (lazy2[o * 2]) lazy1[o * 2] = (lazy1[o * 2] + MOD - lazy1[o]) % MOD; else lazy1[o * 2] = (lazy1[o * 2] + lazy1[o]) % MOD; if (lazy2[o * 2 + 1]) lazy1[o * 2 + 1] = (lazy1[o * 2 + 1] + MOD - lazy1[o]) % MOD; else lazy1[o * 2 + 1] = (lazy1[o * 2 + 1] + lazy1[o]) % MOD; update1(o * 2, l, mid, lazy1[o]); update1(o * 2 + 1, mid + 1, r, lazy1[o]); lazy1[o] = 0; } if (lazy2[o]) { lazy2[o * 2] ^= 1; lazy2[o * 2 + 1] ^= 1; for (int j = 1; j <= 10; j += 2) { node[o * 2].f[j] = MOD - node[o * 2].f[j]; node[o * 2 + 1].f[j] = MOD - node[o * 2 + 1].f[j]; } lazy2[o] = 0; } } void modify1(int o, int l, int r, int ll, int rr, int c) { if (ll <= l && rr >= r) { if (lazy2[o]) lazy1[o] = (lazy1[o] + MOD - c) % MOD; else lazy1[o] = (lazy1[o] + c) % MOD; update1(o, l, r, c); return ; } int mid = (l + r) >> 1; push_down(o, l, r); if (ll <= mid) modify1(o * 2, l, mid, ll, rr, c); if (rr > mid) modify1(o * 2 + 1, mid + 1, r, ll, rr, c); node[o] = merge(node[o * 2], node[o * 2 + 1]); return ; } void modify2(int o, int l, int r, int ll, int rr) { if (ll <= l && rr >= r) { for (int i = 1; i <= 10; i += 2) node[o].f[i] = MOD - node[o].f[i]; lazy2[o] ^= 1; return ; } int mid = (l + r) >> 1; push_down(o, l, r); if (ll <= mid) modify2(o * 2, l, mid, ll, rr); if (rr > mid) modify2(o * 2 + 1, mid + 1, r, ll, rr); node[o] = merge(node[o * 2], node[o * 2 + 1]); return ; } Node query(int o, int l, int r, int ll, int rr) { if (ll <= l && rr >= r) return node[o]; int mid = (l + r) >> 1; push_down(o, l, r); if (rr <= mid) return query(o * 2, l, mid, ll, rr); if (ll > mid) return query(o * 2 + 1, mid + 1, r, ll, rr); Node lc = query(o * 2, l, mid, ll, rr); Node rc = query(o * 2 + 1, mid + 1, r, ll, rr); return merge(lc, rc); } int main(int argc, char ** argv) { freopen("game.in", "r", stdin); freopen("game.out", "w", stdout); int n, m; scanf("%d %d", &n, &m); C[0][0] = 1; for (int i = 1; i <= n; i++) { C[i][0] = 1; for (int j = 1; j <= 10; j++) C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD; } for (int i = 1; i <= n; i++) scanf("%d", &a[i]); build(1, 1, n); for (int i = 1; i <= m; i++) { int l, r, opt; scanf("%d%d%d",&opt, &l, &r); if (opt == 1) { int c; scanf("%d", &c); c = (c % MOD + MOD) % MOD; modify1(1, 1, n, l, r, c); } else if (opt == 2) { modify2(1, 1, n, l, r); } else { int k; scanf("%d", &k); Node o = query(1, 1, n, l, r); printf("%d ", o.f[k] % MOD); } } return 0; }