LOJ刷题记录:SHOI2016(2036-2041)
loj#2036. 「SHOI2015」自动刷题机
直接二分就好了。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
int x[MAXN];
int n, k;
int calc(long long N)
{
long long ans = 0;
int cnt = 0;
for (int i = 1; i <= n; i++) {
// cerr << x[i] << " ";
ans += x[i];
if (ans < 0) ans = 0;
if (ans >= N) cnt++, ans = 0;
}
// cerr << endl;
return cnt;
}
int main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &x[i]);
long long L = 1, R = 1e18, mid;
while (L <= R) {
mid = L+((R-L)>>1);
if (calc(mid) <= k) R = mid-1;
else L = mid+1;
}
long long Low = R+1;
L = 1, R = 1e18;
while (L <= R) {
mid = L+((R-L)>>1);
if (calc(mid) >= k) L = mid+1;
else R = mid-1;
}
long long Up = L-1;
// cerr << calc(Up) << endl;
if (calc(Up) != k || calc(Low) != k || Low > Up) puts("-1");
else cout << Low << " " << Up << endl;
return 0;
}
loj#2037. 「SHOI2015」脑洞治疗仪
以前做过…
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
int dat[MAXN*4], lc[MAXN*4], rc[MAXN*4], l[MAXN*4], r[MAXN*4];
int change[MAXN*4], llen[MAXN*4], rlen[MAXN*4], len[MAXN*4], top = 0, root = 0;
inline int new_node(int opl, int opr)
{ return ++top, l[top] = opl, r[top] = opr, top; }
inline void pdw(int nd) // 1 nh / -1 hole
{
if (!change[nd]) return;
change[lc[nd]] = change[rc[nd]] = change[nd]*(lc[nd]!=0);
dat[nd] = (r[nd]-l[nd]+1)*(change[nd]==1);
llen[nd] = rlen[nd] = len[nd] = (r[nd]-l[nd]+1)*(change[nd]==-1);
change[nd] = 0;
}
inline void update(int nd)
{
pdw(nd), pdw(lc[nd]), pdw(rc[nd]);
if (l[nd] == r[nd]) {
llen[nd] = rlen[nd] = len[nd] = (dat[nd]==0);
return;
}
llen[nd] = llen[lc[nd]]+(dat[lc[nd]] == 0)*llen[rc[nd]];
rlen[nd] = rlen[rc[nd]]+(dat[rc[nd]] == 0)*rlen[lc[nd]];
len[nd] = max(max(len[lc[nd]], len[rc[nd]]), rlen[lc[nd]]+llen[rc[nd]]);
dat[nd] = dat[lc[nd]]+dat[rc[nd]];
}
int pat[MAXN];
void build(int &nd, int l, int r)
{
nd = new_node(l, r);
if (l == r) dat[nd] = pat[r];
else build(lc[nd], l, (l+r)/2), build(rc[nd], (l+r)/2+1, r);
update(nd);
}
void modify(int nd, int opl, int opr, int alc)
{
if (opl > opr) return;
pdw(nd);
if (opl == l[nd] && opr == r[nd]) change[nd] = alc, pdw(nd);
else {
int mid = (l[nd]+r[nd])/2;
if (opr <= mid) modify(lc[nd], opl, opr, alc);
else if (opl > mid) modify(rc[nd], opl, opr, alc);
else modify(lc[nd], opl, mid, alc), modify(rc[nd], mid+1, opr, alc);
pdw(lc[nd]), pdw(rc[nd]), update(nd);
}
}
int query(int nd, int opl, int opr)
{
pdw(nd);
if (opl == l[nd] && opr == r[nd]) return len[nd];
else {
int mid = (l[nd]+r[nd])/2;
pdw(lc[nd]), pdw(rc[nd]);
if (opr <= mid) return query(lc[nd], opl, opr);
else if (opl > mid) return query(rc[nd], opl, opr);
else return max(max(query(lc[nd], opl, mid), query(rc[nd], mid+1, opr)),
min(rlen[lc[nd]], mid-opl+1)+min(llen[rc[nd]], opr-mid));
}
}
void dfs(int nd, int tab = 0)
{
if (!nd) return;
for (int i = 1; i <= tab; i++) putchar(' ');
printf("[%d, %d], dat = %d, llen = %d, rlen = %d, len = %d, change = %d\n", l[nd], r[nd], dat[nd], llen[nd], rlen[nd], len[nd], change[nd]);
dfs(lc[nd], tab+2), dfs(rc[nd], tab+2);
}
int query_sum(int nd, int opl, int opr)
{
if (opl > opr) return 0;
pdw(nd);
int mid = (l[nd]+r[nd])/2;
if (opl == l[nd] && opr == r[nd]) return dat[nd];
else return query_sum(lc[nd], opl, min(opr, mid))+query_sum(rc[nd], max(opl, mid+1), opr);
}
int last_pos(int nd, int k) // in node nd, the first place to have k holes
{
if (l[nd] == r[nd]) return l[nd];
pdw(nd), pdw(lc[nd]), pdw(rc[nd]);
int lp = r[lc[nd]]-l[lc[nd]]+1-dat[lc[nd]];
// cerr << l[nd] << "," << r[nd] << " ; " << k << " ; " << lp << endl;
if (lp >= k) return last_pos(lc[nd], k);
else return last_pos(rc[nd], k-lp);
}
void fix(int ll, int lr, int nl, int nr)
{
int dt = query_sum(root, ll, lr);
// cerr << "-->" << max(0, nl-1)-query_sum(root, 1, nl-1)+dt << "-" << k << endl;
modify(root, ll, lr, -1);
if (dt == 0) return;
int k = last_pos(root, nl-1-query_sum(root, 1, nl-1)+dt);
modify(root, nl, min(nr, k), 1);
}
inline int read()
{
int a = 0, c;
do c = getchar(); while (!isdigit(c));
while (isdigit(c))
a = a*10+c-'0', c = getchar();
return a;
}
int n, m;
int main()
{
n = read(), m = read();
for (int i = 1; i <= n; i++) pat[i] = 1;
build(root, 1, n);
for (int i = 1; i <= m; i++) {
// dfs(root);
int tp, l, r, u, v;
tp = read();
if (tp == 0) l = read(), r = read(), modify(root, l, r, -1);
else if (tp == 1) l = read(), r = read(), u = read(), v = read(), fix(l, r, u, v);
else l = read(), r = read(), printf("%d\n", query(root, l, r));
// for (int j = 1; j <= n; j++) cerr<<query_sum(root, j, j)<<" ";
// cerr << endl;
// dfs(root);
}
return 0;
}
loj#2038. 「SHOI2015」超能粒子炮・改
S(n,k)=∑0≤i≤k(ni) mod 2333=∑0≤i≤k(nmod2333imod2333)(n/2333i/2333)
考虑 i mod 2333 必然成周期性,在每一个周期中 i/2333 又恰好都相等,考虑分块处理,第一部分是完整的块,也就是 mod 2333 为 0..2332 的部分,为:
P=⌊k+12333⌋,Q=(k+1) mod 2333∑0≤i<PS(n mod 2333,2332)(n/2333i)=S(n mod 2333,2332)×S(n/2333,P−1)
第二部分为余下的部分,也就是:
∑0≤i<Q(nmod2333imod2333)(n/2333k/2333)=S(n mod 2333,Q−1)(n/2333k/2333)
这样两部分加起来美滋滋,复杂度 O(log22333(n))
#include <bits/stdc++.h>
using namespace std;
const int mod = 2333;
int c[mod+20][mod+20], f[mod+20][mod+20];
inline int lucas(long long i, long long j)
{
if (i < mod && j < mod) return c[i][j];
return c[i%mod][j%mod]*lucas(i/mod, j/mod)%mod;
}
inline int fun(long long i, long long j)
{
if (i < mod && j < mod) return f[i][j];
return (f[i%mod][mod-1]*fun(i/mod, (j+1)/mod-1)+lucas(i/mod, j/mod)*f[i%mod][(j+1)%mod-1])%mod;
}
int main()
{
c[0][0] = 1;
for (int i = 1; i < mod; i++)
for (register int j = 0; j <= i; j++)
c[i][j] = (c[i-1][j]+(j>=1)*c[i-1][j-1])%mod;
for (int i = 0; i < mod; i++) {
f[i][0] = 1;
for (register int j = 1; j < mod; j++)
f[i][j] = (f[i][j-1]+c[i][j])%mod;
}
// cerr << lucas(12132, 3211) << endl;
int T; scanf("%d", &T);
while (T--) {
long long n, m;
scanf("%lld%lld", &n, &m);
printf("%d\n", fun(n, m));
}
return 0;
}
loj#2039. 「SHOI2015」激光发生器
写了一天的码农计算几何题…
这种题呀…大概是有毒
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 105;
const double eps = 1e-9;
struct point {
double x, y;
friend point operator + (const point &a, const point &b)
{ return (point){a.x+b.x, a.y+b.y}; }
friend point operator - (const point &a, const point &b)
{ return (point){a.x-b.x, a.y-b.y}; }
friend point operator * (double lambda, const point &a)
{ return (point){lambda*a.x, lambda*a.y}; }
friend double operator * (const point &a, const point &b)
{ return a.x*b.y-a.y*b.x; }
inline double len() const
{ return sqrt(x*x+y*y); }
inline double dot(const point &a)
{ return x*a.x+y*a.y; }
double angel(const point &a)
{ return acos((x*a.x+y*a.y)/len()/a.len()); }
point rot(double theta)
{ return (point){cos(theta)*x-sin(theta)*y, sin(theta)*x+cos(theta)*y}; }
};
typedef point vec;
struct line {
point p;
vec v;
inline line normal_left(const point &a)
{ return (line){a, v.rot(M_PI/2)}; }
inline line normal_right(const point &a)
{ return (line){a, v.rot(-M_PI/2)}; }
inline bool on_left(const point &a)
{ return v*(a-p) > 0; }
inline bool on_right(const point &a)
{ return !on_left(a); }
friend point operator * (const line &a, const line &b)
{
double lambda = b.v*(b.p-a.p)/(b.v*a.v);
// cerr << " " << lambda << endl;
return a.p+lambda*a.v;
}
bool along(const point &pt)
{
return (pt-p).dot(v) > eps;
}
inline bool on_line(const point &a)
{
return (a-p).dot(a-(p+v)) <= eps;
}
} px;
int n;
double lambda[MAXN];
line ln[MAXN];
int main()
{
double a, b, c, d, x, y;
scanf("%lf%lf%lf%lf", &a, &b, &c, &d);
px.p = (point){a, b}, px.v = (vec){c, d};
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%lf%lf%lf%lf%lf%lf", &a, &b, &c, &d, &x, &y);
ln[i].p = (point){a, b}, ln[i].v = (point){c-a, d-b}, lambda[i] = x/y;
}
bool pp = 0;
for (int i = 1; i <= 10; i++) {
point fc;
double len = 1e30;
int id;
for (int j = 1; j <= n; j++) {
point pt = px*ln[j];
if (ln[j].on_line(pt) && px.along(pt)) {
if ((pt-px.p).len() < len)
fc = pt, len = (pt-px.p).len(), id = j;
}
}
if (len >= 1e30) break;
line nor = ln[id].on_left(px.p)?ln[id].normal_left(fc):ln[id].normal_right(fc);
double ang = (px.p-fc).angel(nor.v);
if ((px.p-fc)*nor.v < 0) ang = -ang;
ang = ang+ang*lambda[id];
px = (line){fc, (px.p-fc).rot(ang)};
pp = 1;
// cerr << fc.x << " " << fc.y << "," << px.v.x << " " << px.v.y << endl;
printf("%d ", id);
}
if (pp == 0) puts("NONE");
else puts("");
return 0;
}
loj#2040. 「SHOI2015」零件组装机
以前做过…如果有方案,方案唯一,直接找就好了…
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
inline int gcd(int a, int b)
{ return b==0?a:gcd(b, a%b); }
vector<int> vec[MAXN];
int n, T, m;
bool solve(int L, int R)
{
if (L == R) return 1;
if (L > R || vec[L].empty()) return 0;
// if (vec[L].size() == R-L) return solve(L+1, R);
int d = vec[L][vec[L].size()-1]-L, plc = -1, cnt = 0;
for (int i = vec[L].size()-1; i >= 0; i--) {
int tar = vec[L][i]; cnt++;
if (gcd(tar-L, d) == tar-L && (R-L)/(tar-L) == cnt && R-tar+1 >= tar-L) {
plc = tar;
break;
}
}
if (plc == -1) return 0;
// cerr << L << " " << R << " " << plc << endl;
for (int i = L; i < plc; i++) {
int N = (R-i)/(plc-L);
while (N) {
if (vec[i][vec[i].size()-1] != i+(plc-L)*N) return 0;
N--, vec[i].pop_back();
}
}
return solve(L, plc-1)&&solve(plc, R);
}
unordered_set<int> st[MAXN];
int main()
{
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) vec[i].clear();
int flag = 0;
for (int i = 0; i < n; i++) st[i].clear();
for (int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
if (u == v) { flag = 1; }
if (u > v) swap(u,v);
if (!st[u].count(v)) {
st[u].insert(v);
vec[u].push_back(v);
} else flag = 1;
}
if (flag) { puts("NO"); continue; }
for (int i = 0; i < n; i++)
sort(vec[i].begin(), vec[i].end());
if (solve(0, n-1)) puts("YES");
else puts("NO");
}
return 0;
}