2019.10.13考試解題報告
總結
期望得分:\(100 + 30 + 0\)
實際得分:\(100 + 50 + 0\)
神奇的多得了\(20\)分?
花兩個多小時去推\(T1\)的式子,結果是推出來了,慌慌張張差點翻車
去打\(T2\)的暴力,順便打了幾個\(if\),然后就\(30-->50\)?心里有點小激動
\(T3\)沒時間做了……我菜
思路
T1
一開始就想寫正解,發現不會,於是打了個\(40\)分的暴力保底,對暴力的式子進行拆解和優化,得到了下面的過程
要求的是
\[min \sum_{j = 1}^{n} abs(a_i - a_j) * b_j \]
首先去掉絕對值號,發現我們能把這個式子分成兩部分
\[ ans +=\left\{ \begin{aligned} \sum_{j = 1}^{i}(a_i - a_j) * b_j\ (a_i > a_j) \\ \sum_{j = i}^{n}(a_j - a_i) * b_j\ (a_i < a_j) \end{aligned} \right. \]
然后拆解發現,前一部分變成了
\[a_ib_1 - a_1b_1 + a_ib_2 - a_2b_2 + ……a_ib_j-a_jb_j \]
后一部分變成了
\[a_jb_j-a_ib_j+a_{j+1}b_{j+1} -a_ib_{j+1}+……a_nb_n-a_ib_n \]
然后在合並一下子(我懶得寫了)
然后發現我們可以用前綴和!!!
然后就做出來了!!
T2
\(30\)分暴力很好打,暴搜就行了
\(60\)的話,分別枚舉兩個骰子點數,計算出來每種點數和的方案數(除以\(6^n\)得到概率)
如果你扔出了\(i\)點,那你勝利的方案是對手扔出\([1,i)\),從小到大枚舉你的點數,同時
計算對手的前綴和
滿分做法
計算每種點數的概率
計算\(i\)個骰子的概率時,考慮最后一個骰子的點數為\(1-6\)的每種情況,可以從\(i-1\)個骰
子概率轉移過來。
記\(f[i][j]\)表示\(i\)個骰子扔出\(j\)的概率
\(f[i][j] = sum{f[i-1][j-k]/6}(1≤k≤6)\)
遞推即可,復雜度\(O(n²)\)
T3
神仙題神仙題神仙題
代碼
T1
考場滿分
//By:Loceaner
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int N = 1e6 + 11;
struct node {
int a, b, id, c;
} e[N];
bool cmp(node x, node y) {
return x.a < y.a;
}
int n, sum2[N], sum3[N], ans = 0x3f3f3f3f3f3f3f3f;
bool flag = 1;
signed main() {
n = read();
for(int i = 1; i <= n; i++) {
e[i].a = read();
if(i != 1)
if(e[i].a != e[i - 1].a)
flag = 0;
}
for(int i = 1; i <= n; i++) e[i].b = read(), e[i].c = e[i].a * e[i].b;
if(flag) return cout << "0\n", 0;
stable_sort(e + 1, e + 1 + n, cmp);
for(int i = 1; i <= n; i++) {
sum2[i] = sum2[i - 1] + e[i].b;
sum3[i] = sum3[i - 1] + e[i].c;
}
// for(int i = 1; i <= n; i++) {
// int now = 0;
// for(int j = 1; j <= n; j++) {
// now += abs(e[i].a - e[j].a) * e[j].b;
// }
// ans = min(ans, now);
// }
int now = 0;
for(int i = 1; i <= n; i++) {
now = e[i].a * sum2[i - 1] - sum3[i - 1] + (sum3[n] - sum3[i]) - e[i].a * (sum2[n] - sum2[i]);
ans = min(ans, now);
}
cout << ans << '\n';
return 0;
}
/*
6
2 1 3 3 2 4
5 1 1 2 2 2
10
1 2 2 5 6 6 8 10 10 10
9 55 41 2 4 6 3 2 4 10
*/
題解里的正解
#include<bits/stdc++.h>
#define lson (o<<1)
#define rson (o<<1|1)
#define fi first
#define sc second
#define dbg(x) cout<<#x<<" = "<<(x)<<endl;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
using namespace std;
const double pi=acos(-1);
const double eps=1e-6;
inline int lowbit(int x){return x&(-x);}
inline int read(){
int f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
template<typename T> inline T max(T x,T y,T z){return max(max(x,y),z);}
template<typename T> inline T min(T x,T y,T z){return min(min(x,y),z);}
template<typename T> inline T sqr(T x){return x*x;}
template<typename T> inline void checkmax(T &x,T y){x=max(x,y);}
template<typename T> inline void checkmin(T &x,T y){x=min(x,y);}
template<typename T> inline void read(T &x){
x=0;T f=1;char ch;do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do x=x*10+ch-'0',ch=getchar();while(ch<='9'&&ch>='0');x*=f;
}
template<typename A,typename B,typename C> inline A fpow(A x,B p,C yql){
A ans=1;
for(;p;p>>=1,x=1LL*x*x%yql)if(p&1)ans=1LL*x*ans%yql;
return ans;
}
struct FastIO{
static const int S=1310720;
int wpos;char wbuf[S];
FastIO():wpos(0) {}
inline int xchar(){
static char buf[S];
static int len=0,pos=0;
if(pos==len)pos=0,len=fread(buf,1,S,stdin);
if(pos==len)return -1;
return buf[pos++];
}
inline int read(){
int c=xchar(),x=0;
while(c<=32&&~c)c=xchar();
if(c==-1)return -1;
for(;'0'<=c&&c<='9';c=xchar())x=x*10+c-'0';
return x;
}
}io;
//#define read io.read
const int N=1e6+10;
const int yql=1e9+7;
struct Node{
int x,v;
}a[N];
inline bool cmp(Node a,Node b){return a.x<b.x;}
int n,m;
ll cur=0,ans=0,k1,k2;
int main(){
freopen("shiroha1.in","r",stdin);
freopen("shiroha1.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)a[i].x=read();
for(int i=1;i<=n;i++)a[i].v=read();
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)cur=cur+1LL*(a[i].x-a[1].x)*a[i].v;
ans=cur;
for(int i=2;i<=n;i++)k1+=a[i].v;k2=a[1].v;
for(int i=2;i<=n;i++){
//dbg(cur);
//cur=(cur-1LL*k1*(a[i].x-a[i-1].x)%yql+yql)%yql;
//cur=(cur+1LL*k2*(a[i].x-a[i-1].x)%yql)%yql;
cur=cur-1LL*k1*(a[i].x-a[i-1].x);
cur=cur+1LL*k2*(a[i].x-a[i-1].x);
k1-=a[i].v;k2+=a[i].v;
checkmin(ans,cur);
}
printf("%lld\n",ans);
}
T2
暴力
//By:Loceaner
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
int x, y, nowx, nowy, cnta, cntb, cntp;
void dfs2(int tot, int ans) {
if(tot == y) {
nowy = ans;
if(nowx == nowy) cntp++;
else if(nowx > nowy) cnta++;
else cntb++;
return;
}
for(int i = 1; i <= 6; i++) {
dfs2(tot + 1, ans + i);
}
}
void dfs1(int tot, int ans) {
if(tot == x) {
nowx = ans;
dfs2(0, 0);
return;
}
for(int i = 1; i <= 6; i++) {
dfs1(tot + 1, ans + i);
}
}
int main() {
x = read(), y = read();
if(x + y <= 10) {
dfs1(0, 0);
printf("%.2lf%%", ((1.0 * cnta) / (cnta + cntb + cntp)) * 100);
}
else if(x - 7 >= y) cout << "100.00%";
else if(y - 7 >= x) cout << "0.00%";
else if(x > y * 6) cout << "100.00%";
else if(x == y) cout << "50%";
else cout << "0.00%";
return 0;
}
正解
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
double a[1001][7001], sx, sy, ans;
int x, y;
int main() {
scanf("%d%d", &x, &y);
int xy = x > y ? x : y;
for(int i = 1; i <= 6; i++) a[1][i] = 1;
for(int i = 2; i <= xy; i++)
for(int j = i; j <= 6 * i; j++)
for(int k = 1; k <= 6; k++)
if(j > k) a[i][j] += a[i - 1][j - k] / 6.0;
for(int i = x; i <= 6 * x; i++) {
for(int j = y; j <= 6 * y; j++)
sy += a[x][i] * a[y][j];
if(i <= y) continue;
for(int j = y; j <= i - 1; j++)
sx += a[y][j] * a[x][i];
}
ans = sx / sy * 100;
printf("%.2lf%%", ans);
return 0;
}
T3
正解
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 1000010;
const int MAXL = 22;
int rmin[MAXL][MAXN], rmax[MAXL][MAXN];
int n, q;
int a[MAXN];
inline void init_rmq() {
for (int i = 1; i < MAXL; i++) {
for (int j = 0; j + (1 << i) <= n; j++) {
rmin[i][j] = min(rmin[i-1][j], rmin[i-1][j+(1<<(i-1))]);
rmax[i][j] = max(rmax[i-1][j], rmax[i-1][j+(1<<(i-1))]);
}
}
}
inline bool test(int d, int m) {
int l = 0, i;
for (i = 0; i < m && l < n; i++) {
int r = l, smin = 1000000001, smax=0;
for (int j = MAXL - 1; j >= 0; j--) {
if (r + (1 << j) <= n) {
int tmin = rmin[j][r], tmax = rmax[j][r];
if (max(smax, tmax) - min(smin, tmin) <= d) {
smax = max(smax, tmax);
smin = min(smin, tmin);
r += (1 << j);
}
}
}
l = r;
}
return l == n;
}
inline int work(int m) {
int l = 0, r = 1000000001;
while (l < r) {
int mid = (l + r) >> 1;
if (test(mid, m)) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%*d%d", &rmin[0][i]);
rmax[0][i] = rmin[0][i];
}
init_rmq();
scanf("%d", &q);
for (int i = 0; i < q; i++) {
int m;
scanf("%d", &m);
int ans = work(m);
if (ans % 2) printf("%d.5\n", ans/2);
else printf("%d\n", ans/2);
}
}