zoj-3734-LIKE vs CANDLE
problem
打印。有n种收费方式。打印的纸是ai<=x<a(i+1),就是pi钱一张。ai<=a(i+1), pi>=p(i+1)
问打印y张最少多少钱,有m个询问。
think
对于y张纸,找到他在的区间ai<=y<a(i+1),答案就是min(y*pi, aj*pj), j>i
code
const int N = 111111;
LL a[N], b[N], c[N], d[N];
struct point{
LL a;
int id;
}p[N];
LL ans[N];
bool cmp(point x, point y){
return x.a < y.a;
}
int main(){
int T, tt = 0;
int n, m;
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &m);
for(int i = 0; i < n; ++i) scanf("%lld%lld", &a[i], &b[i]);
for(int i = n - 1; i >= 0; --i){
c[i] = a[i]*b[i];
if(i == n-1 || c[i] < d[i+1]) d[i] = c[i];
else d[i] = d[i+1];
}
for(int i = 0; i < m; ++i) {
scanf("%lld", &p[i].a);
p[i].id = i;
}
sort(p, p + m, cmp);
for(int i = 0, j = 0; i < m; ++i){
while(j < n-1 && a[j+1] <= p[i].a) ++j;
if(j == n-1 || p[i].a * b[j] < d[j+1]) ans[p[i].id] = p[i].a * b[j];
else ans[p[i].id] = d[j+1];
}
for(int i = 0; i < m; ++i) printf("%lld\n", ans[i]);
}
return 0;
}
zoj-3732-Graph Reconstruction
problem
给你n[2, 100]个点的度,问是否能构造出一个无向图(没有自环和重边)。
没有就输出没有。有唯一的图就输出这个图。有两个或以上的图就输出其中两个。
think
每次都按度排序。用最大的度依次和第二大第三大……的度(他们的度分别减掉1)匹配。知道完全满足最大的度。
这样出现负数的度数就是没解了。
这样当匹配到第i个点,i+du的点和i+du+1的点(按照从大到小排序后的序号)度数一样,那么这时i选择和i+du的点和i+du+1的点之一哪个都行,就出现了多解。
code
const int N = 111;
struct point{
int id;
int du;
int oig;
}p[N];
int a[N*N], b[N*N];
int cnt, C, n, X, Y;
bool cmp(point x, point y){
return x.du > y.du;
}
bool meng(){
cnt = 0;
X = -1;
for(int i = 0; i < n; ++i){
sort(p + i, p + n, cmp);
if(p[n-1].du < 0) return false;
if(p[i].du >= n - i) return false;
if(p[i].du == 0) return true;
if(p[i].du <= n - i - 2){
int id1 = p[i].du + i;
int id2 = p[i].du + i + 1;
if(X == -1 && p[id1].du == p[id2].du){
X = p[id1].id;
Y = p[id2].id;
C = cnt;
}
}
for(int j = 1; j <= p[i].du; ++j){
--p[i+j].du;
a[cnt] = p[i].id;
b[cnt++] = p[i+j].id;
}
}
return true;
}
int main(){
int T, tt = 0;
while(scanf("%d", &n) != EOF){
for(int i = 0; i < n; ++i){
scanf("%d", &p[i].oig);
p[i].du = p[i].oig;
p[i].id = i + 1;
}
if(meng()){
if(X == -1){
puts("UNIQUE");
printf("%d %d\n", n, cnt);
for(int i = 0; i < cnt; ++i) {
printf("%d", a[i]);
if(i < cnt - 1) putchar(' ');
}
puts("");
for(int i = 0; i < cnt; ++i) {
printf("%d", b[i]);
if(i < cnt - 1) putchar(' ');
}
puts("");
} else {
puts("MULTIPLE");
printf("%d %d\n", n, cnt);
for(int i = 0; i < cnt; ++i) {
printf("%d", a[i]);
if(i < cnt - 1) putchar(' ');
}
puts("");
for(int i = 0; i < cnt; ++i) {
printf("%d", b[i]);
if(i < cnt - 1) putchar(' ');
}
puts("");
printf("%d %d\n", n, cnt);
for(int i = 0; i < cnt; ++i) {
if(a[i] == X && i >= C) printf("%d", Y);
else if(a[i] == Y && i >= C) printf("%d", X);
else printf("%d", a[i]);
if(i < cnt - 1) putchar(' ');
}
puts("");
for(int i = 0; i < cnt; ++i) {
if(b[i] == X && i >= C) printf("%d", Y);
else if(b[i] == Y && i >= C) printf("%d", X);
else printf("%d", b[i]);
if(i < cnt - 1) putchar(' ');
}
puts("");
}
} else {
puts("IMPOSSIBLE");
}
}
return 0;
}
zoj-3733-Skycity
problem
R,r,H, F, S
表示给你一个圆锥去掉尖儿。上面半径r,下面半径R,一共高H,等高的分成F份。
每份装矩形玻璃。每块玻璃不能面积小于S。求最小玻璃面积。
think
tan(pi/n) * RR * 2 * h >= S 得到最大可以装几边形。
code
const double pi = acos(-1.);
int main(){
int T, tt = 0;
double R, r, H, S;
int F;
while(cin >> R >> r >> H >> F >> S){
double ans = 0;
double rr = (R - r) / F;
double h = H / F;
R = r;
for(int i = 0; i < F; ++i){
//根据tan(pi/n) * RR * 2 * h >= S 得:
int n = pi / atan(S/2/R/h);
ans += tan(pi/n) * R * 2 * n;
R += rr;
}
printf("%.3f\n", ans * h);
}
return 0;
}
zoj-3734-LIKE vs CANDLE
problem
一棵树。有三个值,第一个值是权值,第二个值是0或1表示他是否被翻转过,第三个值是0或1表示他是哪边的。
对于每棵子树,可以翻转他,改变这棵子树的每个第三个值,如果他没被翻转过代价是X,否则是Y。
0是根节点,不能翻转。
求最大的第三个值是0的的第一个值的和,减去第三个值是1的的第一个值的和。的差的最大值。
think
树形DP。
dp[i][j]k],i表示i节点,j[0|1]表示是否没翻转过,k[0|1]表示他是否被改变,即被翻转过奇数还是偶数次。
code
const int N = 55555;
const int INF = 1000000000;
vector<int>v[N];
int a[N];
int s[N];
int p[N];
int dp[N][2][2];
int n, X, Y;
int dfs(int x, int sf, int ss){
if(dp[x][sf][ss] != -INF) return dp[x][sf][ss];
int ans = (sf^ss^p[x]) ? -a[x] : a[x];
if(ss != s[x]) ans -= s[x] ? Y : X;
int len = v[x].size();
for(int i = 0; i < len; ++i){
int y = v[x][i];
ans += max(dfs(y, sf^ss, 0), dfs(y, sf^ss, 1));
}
return dp[x][sf][ss] = ans;
}
int main() {
while(scanf("%d%d%d", &n, &X, &Y) != EOF){
int x = 1, y;
for(int i = 1; i <= n; ++i){
scanf("%d%d%d%d", &a[i], &y, &s[i], &p[i]);
if(y==0) x = i;
else v[y].push_back(i);
}
for(int i = 1; i <= n; ++i){
for(int j = 0; j <= 1; ++j){
for(int k = 0; k <= 1; ++k){
dp[i][j][k] = -INF;
}
}
}
int ans = max(dfs(x, 0, 0), dfs(x, 0, 1));
if(ans < 0) puts("HAHAHAOMG");
else printf("%d\n", ans);
for(int i = 0; i <= n; ++i) v[i].clear();
}
return 0;
}
zoj-3735 -Josephina and RPG
problem
有C(m, 3)种队伍,已知第i种队伍打败第j种队伍的概率。告诉你对方一次派出哪种队伍。求你每次都打败对方的最大概率。
第一次选择你可以选择任意一支队伍。第i(i>1)次选择,你可以选择第i-1次你使用的队伍,或者第i-1次对方使用的队伍。
think
dp[i][j] 表示第i次应战,使用j队伍赢的最大概率。
dp[i-1][j]*a[j][id[i]] -> dp[i][j]
dp[i-1][j]*a[id[i-1]][id[i]] -> dp[i][id[i-1]]
code
const int maxn = 10010;
double dp[maxn][200];
double a[200][200];
int id[maxn];
int main () {
int m, n;
while(scanf("%d", &m)!=EOF){
m = m * (m-1) * (m-2) / 6;
for(int i = 0; i < m; ++i) for(int j = 0; j < m; ++j) scanf("%lf", &a[i][j]);
scanf("%d", &n);
scanf("%d", &id[0]);
memset(dp, 0, sizeof(dp));
for(int j = 0; j < m; ++j){
dp[0][j] = a[j][id[0]];
}
for(int i = 1; i < n; ++i){
scanf("%d", &id[i]);
for(int j = 0; j < m; ++j){
dp[i][j] = max(dp[i][j], dp[i-1][j]*a[j][id[i]]);
dp[i][id[i-1]] = max(dp[i][id[i-1]], dp[i-1][j]*a[id[i-1]][id[i]]);
}
}
double ans = 0;
for(int j = 0; j < m; ++j) ans = max(ans, dp[n-1][j]);
printf("%.6f\n", ans);
}
return 0;
}
zoj-3736-Pocket Cube
problem
二阶魔方,给你初态,问n步内,最多可以让几个面颜色一样。
think
暴力。
code
const int K = 24;
struct point{
int a[K];
};
int ans;
int num(point p){
int res = 0;
if(p.a[0] == p.a[1] && p.a[0] == p.a[2] && p.a[0] == p.a[3]) ++res;
if(p.a[6] == p.a[7] && p.a[6] == p.a[12] && p.a[6] == p.a[13]) ++res;
if(p.a[16] == p.a[17] && p.a[16] == p.a[18] && p.a[16] == p.a[19]) ++res;
if(p.a[4] == p.a[5] && p.a[4] == p.a[10] && p.a[4] == p.a[11]) ++res;
if(p.a[20] == p.a[21] && p.a[20] == p.a[22] && p.a[20] == p.a[23]) ++res;
if(p.a[8] == p.a[9] && p.a[8] == p.a[14] && p.a[8] == p.a[15]) ++res;
return res;
}
point t0(point p){
point res = p;
res.a[1] = p.a[7];
res.a[3] = p.a[13];
res.a[7] = p.a[17];
res.a[13] = p.a[19];
res.a[17] = p.a[21];
res.a[19] = p.a[23];
res.a[21] = p.a[1];
res.a[23] = p.a[3];
res.a[9] = p.a[8];
res.a[8] = p.a[14];
res.a[15] = p.a[9];
res.a[14] = p.a[15];
return res;
}
point t1(point p){
point res = p;
res.a[1] = p.a[21];
res.a[3] = p.a[23];
res.a[7] = p.a[1];
res.a[13] = p.a[3];
res.a[17] = p.a[7];
res.a[19] = p.a[13];
res.a[21] = p.a[17];
res.a[23] = p.a[19];
res.a[9] = p.a[15];
res.a[8] = p.a[9];
res.a[15] = p.a[14];
res.a[14] = p.a[8];
return res;
}
point t2(point p){
point res = p;
res.a[3] = p.a[5];
res.a[2] = p.a[11];
res.a[5] = p.a[16];
res.a[11] = p.a[17];
res.a[16] = p.a[14];
res.a[17] = p.a[8];
res.a[14] = p.a[3];
res.a[8] = p.a[2];
res.a[7] = p.a[6];
res.a[6] = p.a[12];
res.a[13] = p.a[7];
res.a[12] = p.a[13];
return res;
}
point t3(point p){
point res = p;
res.a[3] = p.a[14];
res.a[2] = p.a[8];
res.a[5] = p.a[3];
res.a[11] = p.a[2];
res.a[16] = p.a[5];
res.a[17] = p.a[11];
res.a[14] = p.a[16];
res.a[8] = p.a[17];
res.a[7] = p.a[13];
res.a[6] = p.a[7];
res.a[13] = p.a[12];
res.a[12] = p.a[6];
return res;
}
point t4(point p){
point res = p;
res.a[4] = p.a[6];
res.a[5] = p.a[7];
res.a[6] = p.a[8];
res.a[7] = p.a[9];
res.a[8] = p.a[23];
res.a[9] = p.a[22];
res.a[23] = p.a[4];
res.a[22] = p.a[5];
res.a[0] = p.a[2];
res.a[2] = p.a[3];
res.a[1] = p.a[0];
res.a[3] = p.a[1];
return res;
}
point t5(point p){
point res = p;
res.a[4] = p.a[23];
res.a[5] = p.a[22];
res.a[6] = p.a[4];
res.a[7] = p.a[5];
res.a[8] = p.a[6];
res.a[9] = p.a[7];
res.a[23] = p.a[8];
res.a[22] = p.a[9];
res.a[0] = p.a[1];
res.a[2] = p.a[0];
res.a[1] = p.a[3];
res.a[3] = p.a[2];
return res;
}
void solve(point p, int n){
if(n < 0 || ans == 6) return;
ans = max(ans, num(p));
solve(t0(p), n-1);
solve(t1(p), n-1);
solve(t2(p), n-1);
solve(t3(p), n-1);
solve(t4(p), n-1);
solve(t5(p), n-1);
}
int main () {
int n;
while(scanf("%d", &n) != EOF){
point p;
for(int i = 0; i < K; ++i){
scanf("%d", &p.a[i]);
}
ans = 0;
solve(p, n);
printf("%d\n", ans);
}
return 0;
}