A.5246 超级赛亚ACMer
显然要先排序,然后每次在能达到的最大的时候打平,这样的话就可以最大程度的利用k。
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define FIR first
#define SEC second
#define MP make_pair
#define INF 0x3f3f3f3f
#define LL long long
#define ULL unsigned long long
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 100100;
LL a[maxn];
int n, m, k;
bool check()
{
int id = upper_bound(a + 1, a + n + 1, m) - a;
id --;
LL tmp = a[id];
for(int i = id + 1; i <= n; i ++)
{
if(tmp + k < a[i]) return false;
while(tmp + k >= a[i + 1]) i ++;
tmp = a[i];
k --;
}
return true;
}
int main()
{
int T, cas = 1;
scanf("%d", &T);
while(T --)
{
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; i ++)
{
scanf("%I64d", &a[i]);
}
sort(a + 1, a + n + 1);
printf("Case #%d:\n", cas ++);
if(m < a[1])
{
puts("madan!");
}
else if(a[n] <= m)
{
puts("why am I so diao?");
}
else
{
if(check()) puts("why am I so diao?");
else puts("madan!");
}
}
return 0;
}
B.5247 找连续数
n*m=1e7,正好可以暴力,然后对于每个询问,我们只需要看所的k段长度最大值-最小值是否=k-1而且区间里不同元素的个数就行了。最大值和最小值可以用一个单调队列。不同元素的个数可以先离散化,然后用数组统计个数就ok了
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define FIR first
#define SEC second
#define MP make_pair
#define INF 0x3f3f3f3f
#define LL long long
#define ULL unsigned long long
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 100100;
int a[maxn], id[maxn], n, cnt[maxn];
int big[maxn], sml[maxn];
int solve(int k)
{
int l1 = 0, sz1 = 1, l2 = 0, sz2 = 1;
big[0] = a[1];
sml[0] = a[1];
int num = 1;
for(int i = 1; i <= n; i ++) cnt[i] = 0;
cnt[id[1]] ++;
for(int i = 2; i <= k; i ++)
{
if(cnt[id[i]] == 0) num ++;
cnt[id[i]] ++;
while(sz1 > 0 && big[sz1 - 1] < a[i])
{
sz1 --;
}
big[sz1 ++] = a[i];
while(sz2 > 0 && sml[sz2 - 1] > a[i])
{
sz2 --;
}
sml[sz2 ++] = a[i];
}
int ret = 0;
if(num == k && big[l1] - sml[l2] == k - 1) ret ++;
for(int i = k + 1; i <= n; i ++)
{
if(cnt[id[i]] == 0) num ++;
cnt[id[i]] ++;
if(cnt[id[i-k]] == 1) num --;
cnt[id[i-k]] --;
while(sz1 > l1 && big[sz1 - 1] < a[i])
{
sz1 --;
}
big[sz1 ++] = a[i];
if(a[i-k] == big[l1]) l1 ++;
while(sz2 > l2 && sml[sz2 - 1] > a[i])
{
sz2 --;
}
sml[sz2 ++] = a[i];
if(a[i-k] == sml[l2]) l2 ++;
if(num == k && big[l1] - sml[l2] == k - 1) ret ++;
}
return ret;
}
int main()
{
int T, cas = 1, m;
// scanf("%d", &T);
while(scanf("%d%d", &n, &m) != EOF)
{
vector<int> vec;
for(int i = 1; i <= n; i ++)
{
scanf("%d", &a[i]);
vec.push_back(a[i]);
}
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end()), vec.end());
for(int i = 1; i <= n; i ++)
{
id[i] = lower_bound(vec.begin(), vec.end(), a[i]) - vec.begin() + 1;
}
printf("Case #%d:\n", cas ++);
while(m --)
{
int k; scanf("%d", &k);
if(k > n) puts("0");
else printf("%d\n", solve(k));
}
}
return 0;
}
C.5248
序列变换
这种最大值最小的问题,肯定二分+check就行了。对于每个ans,都可以把数变成一个区间,现在就是要看所有的区间能不能有一条上升的折线。简单验证下就可以了。
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define FIR first
#define SEC second
#define MP make_pair
#define INF 0x3f3f3f3f
#define LL long long
#define ULL unsigned long long
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 100200;
int a[maxn];
bool check(int sub, int n)
{
int l = a[1] - sub, r = a[1] + sub;
for(int i = 2; i <= n; i ++)
{
int tl = a[i] - sub, tr = a[i] + sub;
l = max(tl, l + 1);
r = tr;
if(l > r) return false;
}
return true;
}
int main()
{
int n, T, cas = 1;
scanf("%d", &T);
while(T --)
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
{
scanf("%d", &a[i]);
}
int l = 0, r = 10001000;
while(l <= r)
{
int mid = (l + r) >> 1;
if(check(mid, n))
r = mid - 1;
else l = mid + 1;
}
printf("Case #%d:\n%d\n", cas ++, l);
}
return 0;
}
D.5249
KPI
离线做的话其实就是问的区间第k大,划分树或者主席树都可以做。
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define FIR first
#define SEC second
#define MP make_pair
#define LL long long
#define ULL unsigned long long
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
#define MID ((l+r)>>1)
const int maxn = 100100;
const int INF = 0x3f3f3f3f;
int a[maxn];
struct KthNumber
{
int s[maxn], t[20][maxn], num[20][maxn];
void init(int n)
{
for(int i = 1; i <= n; i ++)
{
s[i] = t[0][i] = a[i];
}
sort(s+1, s+n+1);
}
void Build(int c, int l, int r)
{
int lm = MID-l+1, lp = l, rp = MID+1;
for(int i = l; i <= MID; i ++)
lm -= s[i] < s[MID];
for(int i = l; i <= r; i ++)
{
if(i == l) num[c][i] = 0;
else num[c][i] = num[c][i - 1];
if(t[c][i] == s[MID])
{
if(lm)
{
lm --; num[c][i] ++;
t[c+1][lp++] = t[c][i];
}
else t[c+1][rp++] = t[c][i];
}
else if(t[c][i] < s[MID])
{
num[c][i] ++;
t[c+1][lp++] = t[c][i];
}
else t[c+1][rp++] = t[c][i];
}
if(l<r)
Build(c+1, l, MID), Build(c+1, MID+1, r);
}
int Query(int c, int l, int r, int ql, int qr, int k)
{
if(l == r) return t[c][l];
int s, ss;
if(l == ql) s = 0, ss = num[c][qr];
else s = num[c][ql-1], ss = num[c][qr]-num[c][ql-1];
if(k <= ss) return Query(c+1, l, MID, l+s, l+s+ss-1, k);
else return Query(c+1, MID+1, r, MID+1+ql-l-s, MID+1+qr-l-s-ss, k-ss);
}
}sol;
struct Query
{
char op[20];
int x;
}q[maxn];
int main()
{
int n, T, cas = 1;
while(scanf("%d", &n) != EOF)
{
int m = 1;
for(int i = 0; i < n; i ++)
{
scanf("%s", q[i].op);
if(q[i].op[0] == 'i')
{
scanf("%d", &q[i].x);
a[m ++] = q[i].x;
}
}
m --;
// printf("%d===\n", m);
// for(int i = 1; i <= m; i ++)
// {
// printf("%d ", a[i]);
// }puts("");
sol.init(m);
sol.Build(0, 1, m);
int l = 1, r = 0;
printf("Case #%d:\n", cas ++);
for(int i = 0; i < n; i ++)
{
if(q[i].op[0] == 'i')
{
r ++;
}
else if(q[i].op[0] == 'o')
{
l ++;
}
else
{
int k = (r - l + 1) / 2 + 1;
// printf("%d -- %d %d\n", l, r, k);
printf("%d\n", sol.Query(0, 1, m, l, r, k));
}
}
}
return 0;
}
E.5250
三阶魔方
其实就是暴力找出置换,然后最大 公倍数就可以了。
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define FIR first
#define SEC second
#define MP make_pair
#define INF 0x3f3f3f3f
#define LL long long
#define ULL unsigned long long
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
int id[7][4][4];
int s[70];
void init()
{
int tot = 1;
for(int i = 0; i < 6; i ++)
{
for(int j = 0; j < 3; j ++)
{
for(int k = 0; k < 3; k ++)
id[i][j][k] = tot ++;
}
}
}
char op[222];
int tmp[7][4][4];
void Rotate(int i)
{
for(int j = 0; j < 3; j ++)
{
for(int k = 0; k < 3; k ++)
{
tmp[i][j][k] = id[i][2 - k][j];
}
}
}
void idtotmp()
{
for(int i = 0; i < 6; i ++)
{
for(int j = 0; j < 3; j ++)
{
for(int k = 0; k < 3; k ++)
tmp[i][j][k] = id[i][j][k];
}
}
}
void tmptoid()
{
for(int i = 0; i < 6; i ++)
{
for(int j = 0; j < 3; j ++)
{
for(int k = 0; k < 3; k ++)
id[i][j][k] = tmp[i][j][k];
}
}
}
void gaoU(int t)
{
while(t --)
{
idtotmp();
Rotate(0);
for(int i = 0; i < 3; i ++)
{
tmp[1][0][i] = id[2][0][i];
tmp[2][0][i] = id[3][0][i];
tmp[3][0][i] = id[4][0][i];
tmp[4][0][i] = id[1][0][i];
}
tmptoid();
}
}
void gaoR(int t)
{
// t*=2;
while(t --)
{
idtotmp();
// printf("R %d\n", t);
Rotate(2);
for(int i = 0; i < 3; i ++)
{
tmp[0][2][i] = id[1][2 - i][2];
tmp[1][2 - i][2] = id[5][2][i];
tmp[5][2][i] = id[3][i][0];
tmp[3][i][0] = id[0][2][i];
}
tmptoid();
}
}
void gaoF(int t)
{
while(t --)
{
idtotmp();
Rotate(1);
for(int i = 0; i < 3; i ++)
{
tmp[0][i][0] = id[4][2 - i][2];
tmp[4][2 - i][2] = id[5][2 - i][2];
tmp[5][2 - i][2] = id[2][i][0];
tmp[2][i][0] = id[0][i][0];
}
tmptoid();
}
}
void gaoD(int t)
{
while(t --)
{
idtotmp();
Rotate(5);
for(int i = 0; i < 3; i ++)
{
tmp[2][2][i] = id[1][2][i];
tmp[3][2][i] = id[2][2][i];
tmp[4][2][i] = id[3][2][i];
tmp[1][2][i] = id[4][2][i];
}
tmptoid();
}
}
void gaoL(int t)
{
while(t --)
{
idtotmp();
Rotate(4);
for(int i = 0; i < 3; i ++)
{
tmp[1][2 - i][0] = id[0][0][i];
tmp[0][0][i] = id[3][i][2];
tmp[3][i][2] = id[5][0][i];
tmp[5][0][i] = id[1][2 - i][0];
}
tmptoid();
}
}
void gaoB(int t)
{
while(t --)
{
idtotmp();
Rotate(3);
for(int i = 0; i < 3; i ++)
{
tmp[0][i][2] = id[2][i][2];
tmp[2][i][2] = id[5][2 - i][0];
tmp[5][2 - i][0] = id[4][2 - i][0];
tmp[4][2 - i][0] = id[0][i][2];
}
tmptoid();
}
}
LL gcd(LL a, LL b)
{
return b ? gcd(b, a % b) : a;
}
void prt()
{
for(int i = 0; i < 6; i ++)
{
for(int j = 0; j < 3; j ++)
{
for(int k = 0; k < 3; k ++)
{
printf("%02d ", id[i][j][k]);
}puts("");
}puts("");
}puts("----");
}
int main()
{
int T, cas = 1;
scanf("%d", &T);
while(T --)
{
scanf("%s", op);
init();
int len = strlen(op);
for(int i = 0; i < len; i ++)
{
if(op[i] == 'L')
{
if(op[i + 1] == '\'') gaoL(3);
else if(op[i + 1] == '2') gaoL(2);
else gaoL(1);
}
else if(op[i] == 'R')
{
if(op[i + 1] == '\'') gaoR(3);
else if(op[i + 1] == '2') gaoR(2);
else gaoR(1);
}
else if(op[i] == 'U')
{
if(op[i + 1] == '\'') gaoU(3);
else if(op[i + 1] == '2') gaoU(2);
else gaoU(1);
}
else if(op[i] == 'D')
{
if(op[i + 1] == '\'') gaoD(3);
else if(op[i + 1] == '2') gaoD(2);
else gaoD(1);
}
else if(op[i] == 'F')
{
if(op[i + 1] == '\'') gaoF(3);
else if(op[i + 1] == '2') gaoF(2);
else gaoF(1);
}
else if(op[i] == 'B')
{
if(op[i + 1] == '\'') gaoB(3);
else if(op[i + 1] == '2') gaoB(2);
else gaoB(1);
}
}
int tot = 1;
for(int i = 0; i < 6; i ++)
{
for(int j = 0; j < 3; j ++)
{
for(int k = 0; k < 3; k ++)
{
s[id[i][j][k]] = tot ++;
}
}
}
LL ans = 1;
bool vis[100];
int num = 0;
CLR(vis, false);
for(int i = 1; i < tot; i ++)
{
if(vis[i]) continue;
int tmp = 0;
int q = i;
while(!vis[q])
{
vis[q] = true;
tmp ++;
q = s[q];
}
ans = ans / gcd(ans, tmp) * tmp;
num ++;
}
printf("Case #%d:\n%I64d\n", cas ++, ans);
}
return 0;
}
F.5251 矩形面积
显然是凸包最小外接矩形。
#include<stdio.h>
#include<cmath>
#include<algorithm>
#define eps 1e-8
#define N 50010
using namespace std;
struct Point {
double x,y;
Point() {}
Point(double x0,double y0):x(x0),y(y0) {}
};
Point p[N];
int con[N];
int cn;
int n;
double Xmult(Point o,Point a,Point b) {
return (a.x-o.x)*(b.y-o.y)-(b.x-o.x)*(a.y-o.y);
}
double Dmult(Point o,Point a,Point b) {
return (a.x-o.x)*(b.x-o.x)+(a.y-o.y)*(b.y-o.y);
}
int Sig(double a) {
return a<-eps?-1:a>eps;
}
double Dis(Point a,Point b) {
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int cmp(Point a,Point b) {
double d=Xmult(p[0],a,b);
if(d>0)
return 1;
if(d==0 && Dis(p[0],a)<Dis(p[0],b))
return 1;
return 0;
}
double min(double a,double b) {
return a<b?a:b;
}
void Graham() {
int i,ind=0;
for(i=1; i<n; i++)
if(p[ind].y>p[i].y || (p[ind].y==p[i].y) && p[ind].x>p[i].x)
ind=i;
swap(p[ind],p[0]);
sort(p+1,p+n,cmp);
con[0]=0;
con[1]=1;
cn=1;
for(i=2; i<n; i++) {
while(cn>0 && Sig(Xmult(p[con[cn-1]],p[con[cn]],p[i]))<=0)
cn--;
con[++cn]=i;
}
int tmp=cn;
for(i=n-2; i>=0; i--) {
while(cn>tmp && Sig(Xmult(p[con[cn-1]],p[con[cn]],p[i]))<=0)
cn--;
con[++cn]=i;
}
}
double Solve() {
int t,r,l;
double ans=999999999;
t=r=1;
if(cn<3)
return 0;
for(int i=0; i<cn; i++) {
while(Sig( Xmult(p[con[i]],p[con[i+1]],p[con[t+1]])-
Xmult(p[con[i]],p[con[i+1]],p[con[t]]) )>0)
t=(t+1)%cn;
while(Sig( Dmult(p[con[i]],p[con[i+1]],p[con[r+1]])-
Dmult(p[con[i]],p[con[i+1]],p[con[r]]) )>0)
r=(r+1)%cn;
if(!i) l=r;
while(Sig( Dmult(p[con[i]],p[con[i+1]],p[con[l+1]])-
Dmult(p[con[i]],p[con[i+1]],p[con[l]]) )<=0)
l=(l+1)%cn;
double d=Dis(p[con[i]],p[con[i+1]]);
double tmp=Xmult(p[con[i]],p[con[i+1]],p[con[t]])*
( Dmult(p[con[i]],p[con[i+1]],p[con[r]])-
Dmult(p[con[i]],p[con[i+1]],p[con[l]]) )/d/d;
ans=min(ans,tmp);
}
return ans;
}
int main() {
int i;
int T, cas = 1;
scanf("%d", &T);
while(T --) {
scanf("%d",&n);
n *= 4;
for(i=0; i<n; i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
Graham();
printf("Case #%d:\n%.0f\n",cas ++, Solve());
}
return 0;
}