2019湖南多校第一场-20190310

版权声明:转载请说明,欢迎交流! https://blog.csdn.net/qq_39599067/article/details/88389924

(有问题欢迎提出来

A:Altruistic Amphibians

Upsolved.
神奇的1G1G内存,神奇的6s6s,神奇时间空间复杂度约1e81e8dpdp
(完全没注意到这个1G1G内存。

dp[i]dp[i]表示体重为ii的青蛙最高能站的高度
枚举每个青蛙ii的贡献,那么体重为j(jwi1)j(j\le w_i-1)的青蛙组合可以站在第ii个青蛙wiw_i身上,俩一起的体重为j+wij+w_i
所以转移方程:dp[j]=max(dp[j+wi]+hi)dp[j] = max(dp[j+w_i]+h_i)
并且要把青蛙按wiw_i从大到小排序,这样才能保证状态j+wij+w_i被计算过

#include<bits/stdc++.h>
#define fi first
#define se second
#define eb emplace_back
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;

const int INF = 0x3f3f3f3f;
const int MXN = 1e5 + 2;
const int mod = 1e8 + 2;
int n, m, d;
LL dp[mod];
struct lp {
    int l, w, h;
}cw[MXN];
bool cmp(const lp &a, const lp &b) {
    return a.w > b.w;
}
int main() {
    scanf("%d%d", &n, &m);
    int sum = 0, cnt = 0;
    for(int i = 0; i < n; ++i) {
        scanf("%d%d%d", &cw[i].l, &cw[i].w, &cw[i].h);
        sum += cw[i].w;
        //dp[cw[i].w] = max(dp[cw[i].w], (LL)cw[i].h);
    }
    sort(cw, cw + n, cmp);
    for(int i = 0, l, w, h; i < n; ++i) {
        l = cw[i].l, w = cw[i].w, h = cw[i].h;
        for(int j = 1; j < w && j + w < mod; ++j) {
            dp[j] = max(dp[j], dp[j+w] + h);
        }
        if(dp[w] + l > m) ++ cnt;
    }
    printf("%d\n", cnt);
    return 0;
}

B:Baby Bites

Solved.
ii个东西应该是ii或字符串。
队友秒了。

int a[maxn];
int main() {
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        a[i]=rint(s);//把字符串变成数字,若不是数字返回-1
    }
    int flag=1;
    for(int i=1;i<=n;i++){
        if(a[i]==-1)continue;
        else {
            if(a[i]!=i)flag=0;
        }
    }
    puts(flag?"makes sense":"something is fishy");
    return 0;
}

C:Code Cleanups

Solved.
队友讲的题意,我硬是没搞懂。。。当我懂题意时,发现队友忘了一个条件,改完就过了。

int n;
int a[666];
int main() {
    scanf("%d", &n);
	int cnt = 0, cur = 0, num = 0;
	for(int i = 0; i < n; ++i) {
		scanf("%d", &a[i]);
		if(cur == 0) cur = a[i], num = 1;
		else if(a[i]*num - cur >= 20) {
			cnt ++;cur = a[i];num = 1;
		}else if(a[i]*num - cur == 19) {
			cnt ++;cur = 0;num = 0;
		}else {
			num ++;cur += a[i];
		}
	}
	if(cur != 0) cnt ++;
	printf("%d\n", cnt);
    return 0;
}

D:Delivery Delays

Upsolved.
共有n(1000)n(1000)个点,k(1000)k(1000)个订单,总店在1号点,每个订单的下单时间是sis_i,下单地点是uiu_i,准备好物品时间是tit_i
保证i&lt;ji\lt jsi&lt;sj,ti&lt;tjs_i\lt s_j, t_i\lt t_j。然后货物必须按照下单顺序配送!
问某种配送方案下的顾客最长的等待时间最小,求出最小的最大值。

最小化最大值考虑二分答案midmid
配送方案肯定是一段一段的,就是说把某一段订单等他们全部做好之后再配送。
枚举每个点的最优分段点,求出从每个订单终点回到起点的最短时间。
这个过程中必须保证每个顾客的等待时间小于等于midmid

#include<bits/stdc++.h>
#define fi first
#define se second
#define eb emplace_back
#define  mem(a,b)    memset(a,b,sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
const int MXN = 1e3 + 7;
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;

int n, m, vis[MXN], tot, head[MXN];
LL d[MXN], dis[MXN][MXN];
struct lp {
    int s, u, t;
}cw[MXN];
struct Edge {
    int v, nxt;
    LL w;
} edge[MXN*100];
void init() {
    tot = 0;
    mem ( head, -1 );
}
void add ( int u, int v, LL w ) {
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].nxt = head[u];
    head[u] = tot++;
}
struct node {
    LL d, v;
    node ( LL d, LL v ) : d ( d ), v ( v ) {}
    bool operator < ( const node & a ) const {
        return d > a.d;
    }
};
priority_queue<node>q;
void dijstar ( int s ) {
    while ( !q.empty() ) q.pop();
    for ( int i = 0 ; i <= n ; i++ ) d[i] = INFLL, vis[i] = 0;
    d[s] = 0;
    q.push ( node ( 0, s ) );
    while ( !q.empty() ) {
        node temp = q.top();
        q.pop();
        int u = temp.v;
        if ( vis[u] ) continue;
        vis[u] = 1;
        for ( int i = head[u]; ~i ; i = edge[i].nxt ) {
            int v = edge[i].v;
            if ( d[v] > d[u] + edge[i].w && !vis[v] ) {
                d[v] = d[u] + edge[i].w;
                q.push ( node ( d[v], v ) );
            }
        }
    }
}
LL dp[MXN], len[MXN][MXN], late[MXN][MXN];
bool check(LL mid, int Q) {//等待时间不能超过mid
    for(int i = 1; i <= Q; ++i) dp[i] = INFLL;
    dp[0] = 0;
    for(int i = 1; i <= Q; ++i) {
        LL st = 0, Max = INFLL;
        for(int j = 1; j <= i; ++j) {//枚举分段点
            st = max(dp[j-1], (LL)cw[i].t);
            if(late[j][i] + st <= mid) {
                Max = min(Max, len[j][i] + st);
            }
        }
        if(Max == INFLL) return false;
        dp[i] = Max;
    }
    return dp[Q] < INFLL;
}
void gao(int n) {
    for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) len[i][j]=late[i][j]=INFLL;
    for(int i = 1; i <= n; ++i) {
        LL all = 0, waite = -INFLL;
        int ls = 1;
        for(int j = i; j <= n; ++j) {
            all += dis[ls][cw[j].u];
            waite = max(waite, all - cw[j].s);
            late[i][j] = waite;
            len[i][j] = all + dis[1][cw[j].u];
            ls = cw[j].u;
        }
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("E://ADpan//in.in", "r", stdin);
    //freopen("E://ADpan//out.out", "w", stdout);
#endif
    scanf ( "%d%d", &n, &m );
    init();
    for ( int i = 0, u, v ; i < m; i++ ) {
        LL w;
        scanf ( "%d%d%lld", &u, &v, &w );
        add ( u, v, w ), add ( v, u, w );
    }
    for ( int i = 1 ; i <= n ; i++ ) {
        dijstar ( i );
        for(int j = 1; j <= n; ++j) dis[i][j] = d[j];
    }
    int Q; scanf("%d", &Q);
    for(int i = 1; i <= Q; ++i) {
        scanf("%d%d%d", &cw[i].s, &cw[i].u, &cw[i].t), assert(cw[i].t>=cw[i].s);
    }
    gao(Q);
    LL L = 0, R = 1e15, ans = 0, mid;
    while(L <= R) {
        mid = (L + R) >> 1;
        if(check(mid, Q)) ans = mid, R = mid - 1;
        else L = mid + 1;
    }
    printf("%lld\n", ans);
    return 0;
}

E:Explosion Exploit

Upsolved.

敌我分别最多有55个随从,每个随从最高66滴血,共有dd点伤害。
伤害的分配方式时每次等概率随机选择场上存活的一个随从造成11点伤害。问敌方全死亡的概率。
记忆化搜索:

  • 用一个1212为整数记录敌我血量为ii的随从的数量。搜索的同时记录场上随从的数量和剩余的伤害数。
  • 边界条件:敌方全部阵亡,返回11;伤害剩余00,返回00
  • 然后枚举这次会是哪方血量为多少的随从受到11点伤害,这个概率是ax[i]sumbx[i]sum\frac {ax[i]}{sum}或\frac {bx[i]}{sum},累加这个概率乘以下个状态搜索出来的概率。

比赛的时候和队友一直推组合数的公式,现在还不是很清楚这个方法的正确性。就是把随从当成物品,当成一个摆放问题。。。

const int INF = 0x3f3f3f3f;
const int MXN = 1e3 + 7;
const int mod = 1e9 + 7;
int n, m, d;
int ar[6], br[6], ax[7], bx[7];
LL F[MXN], C[MXN][MXN];
LL ksm(LL a, int b) {
    LL res = 1;
    for(;b;b>>=1,a=a*a%mod) {
        if(b&1) res=res*a%mod;
    }
    return res;
}
LL getab() {
    LL res = 0;
    for(int i = 1; i < 7; ++i) res = res * 10 + ax[i];
    for(int i = 1; i < 7; ++i) res = res * 10 + bx[i];
    return res;
}
LL getb() {
    LL res = 0;
    for(int i = 1; i < 7; ++i) res = res * 10 + bx[i];
    return res;
}
map<LL , double> mp;
double solve(int sum, int aim) {
    LL absum = getab(), bsum = getb();
    if(mp.count(absum)) return mp[absum];
    if(bsum == 0) return 1;
    if(aim == 0) return 0;
    double ans = 0;
    for(int i = 1, ret; i <= 6; ++i) {
        if(ax[i] == 0) continue;
        -- ax[i];
        ++ ax[i-1];
        ret = sum - (i == 1);
        ans += 1.0*(ax[i]+1)/sum*solve(ret, aim-1);
        ++ ax[i];
        -- ax[i-1];
    }
    for(int i = 1, ret; i <= 6; ++i) {
        if(bx[i] == 0) continue;
        -- bx[i];
        ++ bx[i-1];
        ret = sum - (i == 1);
        ans += 1.0*(bx[i]+1)/sum*solve(ret, aim-1);
        ++ bx[i];
        -- bx[i-1];
    }
    mp[absum] = ans;
    return ans;
}
int main() {
    //init();
    scanf("%d%d%d", &n, &m, &d);
    int t = 0,sum = 0;
    for(int i = 1; i <= n; ++i) scanf("%d", &ar[i]),++ax[ar[i]],sum+=ar[i];
    for(int i = 1; i <= m; ++i) scanf("%d", &br[i]),++bx[br[i]],sum+=br[i];
    for(int i = 1; i <= 6; ++i) t += ax[i] + bx[i];
    printf("%.10f\n", solve(t, min(d,sum)));
    return 0;
}

F:Firing the Phaser

Unsolved.


G:Game Scheduling

Unsolved.


H:House Lawn

Solved.
注意:题目说了除草机是有电则一定在工作,电量用完后立马充电,充完电立马开始工作。

之前一直没注意到这个条件,写着有点懵逼,队友告诉我这个条件时,我正沉迷于E题的推公式。。。一段时间后,队友就把这题改出来了。

你就算一下每台机器每周10080时间内的平均除草量,如果大于你家草坪大小,则这个机器在可选范围内。然后记录一下可选范围最便宜的几个就行了。

平均除草量是:10080.0*t*c/(t*1.0+r) = \frac{工作时间}{工作加充电时间}*总时间*单位时间除草量
当然你也可以用lcmlcm写,不过用doubledouble就够了,其实差不多的。

const int INF = 0x3f3f3f3f;
const int MXN = 1e6 + 2;
const int mod = 1e9 + 7;
int n, m;
string name[MXN];
int stak[MXN], top = 0;
double solve(LL c, LL t, LL r) {
    return 10080.0*t*c/(t*1.0+r);
}
int main() {
    scanf("%d%d", &m, &n);
    getchar();
    int ans = INF;
    for(int i = 0, len; i < n; ++i) {
        string s;
        getline(cin, s);
        len = s.length();
        int tmp = 0;
        for(; s[tmp] != ',';++tmp) ;
        name[i] = s.substr(0, tmp);
        int p = 0, c = 0, t = 0, r = 0;
        for(++tmp; s[tmp] != ',';++tmp) p = p*10+s[tmp]-'0';
        for(++tmp; s[tmp] != ',';++tmp) c = c*10+s[tmp]-'0';
        for(++tmp; s[tmp] != ',';++tmp) t = t*10+s[tmp]-'0';
        for(++tmp; tmp < len;++tmp) r = r*10+s[tmp]-'0';
        if(solve(c, t, r) >= m && p <= ans) {
            if(p == ans) stak[++top] = i;
            else stak[1] = i, top = 1;
            ans = p;
        }
    }
    for(int i = 1; i <= top; ++i) {
        cout << name[stak[i]] << "\n";
    }
    if(top == 0) cout << "no such mower\n";
    return 0;
}

I:Intergalactic Bidding

Solved.
比赛没有ideaideasublimesublime用着不习惯,然后队友拿c++c++大数板子过了。
赛后拿javajava补了一发,感觉就是。。。没有ideaidea拿命写javajava啊。

问题转化为给你一个序列和一个数,要你用序列中的一些数字凑出和为给定的那个数。
这题最重要的就是有一个条件每个人的出价必须至少是当时最高出价的两倍。那么你所选的方案就是固定的了。

拍序后按大开始选,只要能选就必须选。因为这个数字后面的所有数之和是要小于当前这个可选数字的,你连当前这个最大的都不选,那更不可能凑出答案来了。
最简单的例子就是:用8,4,2,18,4,2,1凑出99来,你能给出两种方案吗?

import java.io.*;
import java.lang.reflect.Array;
import java.util.*;
import java.math.*;

public class Main {
    static class lp{
        public String s;
        public BigInteger w;
        lp(){
            s = "";
            w = BigInteger.ZERO;
        }
    }
    public static void main(String[] args) throws FileNotFoundException {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        Task solver = new Task();
        solver.solve(1, in, out);
        out.close();
    }

    static class Task {
        static int MXN = 300005;
        static int mod = 1000000007;
        static int BASE_MAX = 62;
        long[] invF = new long[MXN];
        List<lp> cw = new ArrayList<lp>();
        int[] ar = new int[MXN];
        int n;
        public void solve(int testNumber, InputReader cin, PrintWriter cout) {
            n = cin.nextInt();
            BigInteger sum = cin.nextBigInteger();
            for(int i = 0; i < n; ++i) {
                lp tmp = new lp();
                String x = cin.nextLine();
                String[] ss = x.split(" ");
                tmp.s = ss[0];
                tmp.w = BigInteger.ZERO;
                int len = ss[1].length();
                for(int j = 0; j < len; ++j) tmp.w = tmp.w.multiply(BigInteger.valueOf(10)).add(BigInteger.valueOf(ss[1].charAt(j)-'0'));
                cw.add(tmp);
            }
            Collections.sort(cw,C);
            /*for(int i = 0; i < n; ++i) {
                cout.println(cw.get(i).w);
            }
            for(int i = 0; i < n; ++i) {
                cout.println(cw.get(i).s);
            }*/
            int flag = 1, cnt = 0;
            BigInteger tsum = sum;
            for(int i = 0; i < n; ++i) {
                if(sum.compareTo(cw.get(i).w) >= 0) {
                    sum = sum.subtract(cw.get(i).w);
                    ++ cnt;
                }
            }
            if(sum == BigInteger.ZERO) {
                cout.println(cnt);
                for(int i = 0; i < n; ++i) {
                    if(tsum.compareTo(cw.get(i).w) >= 0) {
                        tsum = tsum.subtract(cw.get(i).w);
                        cout.println(cw.get(i).s);
                    }
                }
            }else {
                cout.println(0);
            }
        }
        static class pair {
            long x;
            long y;
            long answer;
        }
        public long ksm(int a, int b) {
            long res = 1, tmp = a;
            while(b != 0) {
                if(b % 2 == 1) {
                    res = res * tmp;
                    if(res >= mod) res %= mod;
                }
                tmp = tmp * tmp;
                if(tmp >= mod) tmp %= mod;
                b >>= 1;
            }
            return res;
        }
        public void pre_init() {
            invF[0] = invF[1] = 1;
            for(int i = 2; i < MXN; ++i) {
                invF[i] = (mod - mod/i)*invF[mod%i];
                if(invF[i] >= mod) invF[i] %= mod;
            }
        }
    }
    static Comparator<lp> C = new Comparator() {
        public int compare(Object o1, Object o2) {
            lp x1 = (lp)o1;
            lp x2 = (lp)o2;
            if(x1.w.compareTo(x2.w) <= 0) return 1;
            else return -1;
        }
    };
    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) throws FileNotFoundException {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }
        public boolean hasNext() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {//hasMoreElements
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (Exception e) {//IOException
                    return false;
                    //throw new RuntimeException(e);
                }
            }
            return true;
        }
        public String next() {
            if(hasNext()) return tokenizer.nextToken();
            return null;
        }
        public int nextInt() {
            return Integer.parseInt(next());
        }
        public Long nextLong() {
            return Long.parseLong(next());
        }
        public double nextDouble() {
            return Double.parseDouble(next());
        }

        public BigInteger nextBigInteger() {
            return new BigInteger(next());
        }
        public BigDecimal nextBigDecimal() {
            return new BigDecimal(next());
        }
        String nextLine() {
            String str = "";
            try {
                str = reader.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }
    }

}

J:Jumbled String

Solved.
直接交给队友了。

补了一下,感觉坑点还是很多的。大致写法就是往00里面插11,直到合法。当然有很多种不合法的情况,你要多多注意才行。

const int INF = 0x3f3f3f3f;
const int MXN = 1e6 + 2;
const int mod = 1e9 + 7;
LL a, b, c, d;
LL n, m;
int flag = 1;
int main() {
    scanf("%lld%lld%lld%lld", &a, &b, &c, &d);
    for(n = 0; n < 100000; ++n) {
        if(n * (n-1)/2 == a) {
            break;
        }else if(n * (n-1)/2 > a) break;
    }
    for(m = 0; m < 100000; ++m) {
        if(m * (m-1)/2 == d) {
            break;
        }else if(m * (m-1)/2 > d) break;
    }
    if(n == 0 && (b || c)) n = 1;
    if(m == 0 && (b || c)) m = 1;
    if(n * (n - 1)/2 != a) flag = 0;
    if(m * (m - 1)/2 != d) flag = 0;
    if(flag == 0) {
        cout << "impossible\n";
        return 0;
    }
    string ans;
    for(int i = 0; i < n; ++i) ans += '0';//insert 让你在第i个位置
    if(b != 0 && (n == 0 && m == 0)) {
        cout << "impossible\n";
        return 0;
    }
    if(c != 0 && (n == 0 && m == 0)) {
        cout << "impossible\n";
        return 0;
    }
    while(b && m) {
        if(b >= n) {
            ans.insert(n, "1");
            b -= n;
        }else {
            ans.insert(b, "1");
            c -= n-b;
            b = 0;
        }
        -- m;
    }
    if(b != 0) flag = 0;
    if(m < 0 || c < 0) flag = 0;
    if(m * n != c) flag = 0;
    else {
        for(int i = 0; i < m; ++i) ans.insert(0, "1");
    }
    if(flag == 0) {
        cout << "impossible\n";
    }else cout<<ans<<"\n";
    return 0;
}

K:King’s Colors

Solved.
队友讲完题意。思考了几分钟,发现是个sbsb题,然后就拿了一血。

LL ksm(LL a, int b) {
	LL res = 1;
	for(;b;b>>=1,a=a*a%mod) {
		if(b&1) res = res*a%mod;
	}
	return res;
}
LL C[3005][3005];
int main() {
	C[1][1] = 1;
	for(int i = 2; i < 3000; ++i) {
		for(int j = 1; j <= i; ++j) {
			C[i][j] = (C[i-1][j]+C[i-1][j-1])%mod;
		}
	}
    LL n, k;
    scanf("%lld%lld",&n, &k);
    for(int i = 1, x; i < n; ++i) {
		scanf("%d", &x);
    }
    LL ans = 0, tmp;
    for(LL i = k, j = 0; i >= 2; --i, j = !j) {
		tmp = C[k+1][i+1] * i % mod * ksm(i-1, n-1) % mod;
		if(j == 0) ans = (ans+tmp)%mod;
		else ans = (ans - tmp)%mod;
    }
    printf("%lld\n", (ans+mod)%mod);
    return 0;
}
展开阅读全文

没有更多推荐了,返回首页