浙江工业大学第十九届“杭银理财杯”大学生程序设计竞赛暨全国邀请赛 部分题解

7-2 Puzzle

补题:对A,B,C序列哈希,同时将A左移 [0,n-1] 位的哈希值作为key、左移位数作为value,将其存入map中,然后枚举B左移 [0,n-1] 位,在map中寻找是否存在哈希值与枚举的B的哈希值-C的哈希值相等,枚举过程中维护答案。复杂度 O ( n l o g n ) O(nlogn) O(nlogn),枚举 O ( n ) O(n) O(n),map存取值 O ( l o g n ) O(logn) O(logn)
如果对于hash不了解可以学习参考我的博客:[哈希传送门]
tips.该代码未交,仅供参考

code

#include 
using namespace std;

#define ull unsigned long long
#define maxn 100005

const ull p = 1000000007;
ull a[maxn], b[maxn], c[maxn], B[maxn];
int n, ans = p;

map<ull, int> mp;

void init(int n) {
    B[0] = 1;
    for (int i = 1; i <= n; i++) B[i] = B[i - 1] * p;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    init(n);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        a[i] += a[i - 1] * p;
    }
    for (int i = 1; i <= n; i++) {
        cin >> b[i];
        b[i] += b[i - 1] * p;
    }
    for (int i = 1; i <= n; i++) {
        cin >> c[i];
        c[i] += c[i - 1] * p;
    }
    for (int i = 0; i < n; i++) {
        ull tmp = (a[n] - a[i] * B[n - i]) * B[i] + a[i];
        mp[tmp] = i;
    }
    for (int i = 0; i < n; i++) {
        ull tmp = (b[n] - b[i] * B[n - i]) * B[i] + b[i];
        if (mp.count(c[n] - tmp)) {
            ans = min(ans, mp[c[n] - tmp] + i);
        }
    }
    if (ans == p)
        cout << "-1";
    else
        cout << ans;
    return 0;
}

7-6 Tree Game

构造,从叶子节点开始 dfs同时涂色即可保证最多一个ugly node

Accepted code

#include 
using namespace std;
#define ll long long
#define bug printf("***********\n");
#define endl "\n"
const ll N = 3e5 + 7;

int n, k;
vector<int> road[N];
int du[N];
bool is[N];
int cnt = 0;
void dfs(int dex) {
    cnt++;
    printf("%d ", dex);
    if (cnt == k) {
        return;
    }
    for (int i = 0; i < road[dex].size(); i++) {
        int to = road[dex][i];
        if (!is[to]) {
            is[dex] = true;
            dfs(to);
        }
        if (cnt == k) {
            return;
        }
    }
}
int main() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        road[u].push_back(v);
        road[v].push_back(u);
        du[u]++;
        du[v]++;
    }
    if (n == 1) {
        cout << 1 << endl;
        return 0;
    }
    int start = -1;
    for (int i = 1; i <= n; i++) {
        if (du[i] == 1) {
            start = i;
            break;
        }
    }
    is[start] = true;
    dfs(start);
}

7-8 Minimum Edit Distance

手玩发现,S、T任意串即是答案

Accepted code

#include 
using namespace std;
string s1,s2;
int main(){
    cin>>s1>>s2;
    cout<<s1<<endl;
    return 0;
}

7-9 Rounding Master

四舍五入,要入q至少1.5,同时 1.5 102 {1.5}^{102} 1.5102已经大于1e18。所以当k>102即可输出1.5,k=1和n=1要特判,同时double精度不够,要用long double

Accepted code

#include
using namespace std;

#define db long double
const db eps=1e-7;
db n,x=1;long long k;

bool cmp(db a,db b){
    return fabs(a-b)<=eps;
}

bool ck(db q){
    x=1;
    for(int i=0;i<k;i++){
        x*=q;
        x=round(x);
    }
    return (x>n||cmp(x,n));
}

int main(){
    scanf("%Lf%lld",&n,&k);
    if(k==1){
        printf("%.6Lf",n-0.5);
        return 0;
    }
    if(n==1){
        printf("0.5");
        return 0;
    }
    if(k>=110){
        printf("1.5");
        return 0;
    }
    db l=1.5,r=n-0.5;
    while(!cmp(l,r)){
        db mid=l+(r-l)*0.5;
        if(ck(mid)){
            r=mid;
        }else{
            l=mid;
        }
    }
    printf("%.6Lf",r);
    return 0;
}

7-11 Pairing Game

最后一个脑溢血小错误差两分钟没调出来,不过思路是应该没错,从1到n加点,三个线段树,存区间所有数,区间左端点数,区间右端点数。题中要求倒着删点,我们可以正着加点统计答案再逆序输出。
每次增加两个点i时,答案先增加两个点中间的数字的个数。同时这两个点对答案的贡献是左端点左侧的点中去掉成对点的点数,右端点右侧同理,即代码中的lnum与rnum,三个部分构成该轮答案增加的贡献。复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
如果对线段树不了解可以参考学习我的博文:[线段树传送门]
tips.该代码未交,仅供参考

code

#include 
using namespace std;
#define ll long long
#define maxn 300005
#define dl (d << 1)
#define dr (d << 1 | 1)

ll n, a[maxn * 2], idx[maxn][2];
long long sum;
struct node {
    ll l, r, sum;
} sgt[maxn << 3], lt[maxn << 3], rt[maxn << 3];

void build(ll d, ll l, ll r) {
    sgt[d].l = lt[d].l = rt[d].l = l;
    sgt[d].r = lt[d].r = rt[d].r = r;
    sgt[d].sum = lt[d].sum = rt[d].sum = 0;
    if (l == r) return;
    ll mid = l + r >> 1;
    build(dl, l, mid);
    build(dr, mid + 1, r);
}

void pushup(ll d) { sgt[d].sum = sgt[dl].sum + sgt[dr].sum; }

void pushupl(ll d) { lt[d].sum = lt[dl].sum + lt[dr].sum; }

void pushupr(ll d) { rt[d].sum = rt[dl].sum + rt[dr].sum; }

ll query(ll d, ll l, ll r) {
    if (l <= sgt[d].l && sgt[d].r <= r) return sgt[d].sum;
    ll mid = sgt[d].l + sgt[d].r >> 1, ret = 0;
    if (l <= mid) ret += query(dl, l, r);
    if (r > mid) ret += query(dr, l, r);
    return ret;
}

ll queryl(ll d, ll l, ll r) {
    if (l <= lt[d].l && lt[d].r <= r) return lt[d].sum;
    ll mid = lt[d].l + lt[d].r >> 1, ret = 0;
    if (l <= mid) ret += queryl(dl, l, r);
    if (r > mid) ret += queryl(dr, l, r);
    return ret;
}

ll queryr(ll d, ll l, ll r) {
    if (l <= rt[d].l && rt[d].r <= r) return rt[d].sum;
    ll mid = rt[d].l + rt[d].r >> 1, ret = 0;
    if (l <= mid) ret += queryr(dl, l, r);
    if (r > mid) ret += queryr(dr, l, r);
    return ret;
}

void insert(ll d, ll pos) {
    if (sgt[d].l == sgt[d].r) {
        ++sgt[d].sum;
        return;
    }
    ll mid = sgt[d].l + sgt[d].r >> 1;
    if (pos <= mid) insert(dl, pos);
    if (mid < pos) insert(dr, pos);
    pushup(d);
}

void insertl(ll d, ll pos) {
    if (lt[d].l == lt[d].r) {
        ++lt[d].sum;
        return;
    }
    ll mid = lt[d].l + lt[d].r >> 1;
    if (pos <= mid) insertl(dl, pos);
    if (mid < pos) insertl(dr, pos);
    pushupl(d);
}

void insertr(ll d, ll pos) {
    if (rt[d].l == rt[d].r) {
        ++rt[d].sum;
        return;
    }
    ll mid = rt[d].l + rt[d].r >> 1;
    if (pos <= mid) insertr(dl, pos);
    if (mid < pos) insertr(dr, pos);
    pushupr(d);
}
stack<long long> ans;
int main() {
    scanf("%d", &n);
    for (ll i = 1, sz = 2 * n; i <= sz; i++) {
        scanf("%d", &a[i]);
        if (!idx[a[i]][0])
            idx[a[i]][0] = i;
        else
            idx[a[i]][1] = i;
    }
    build(1, 1, 2 * n);
    for (ll i = 1; i <= n; i++) {
        ans.push(sum);
        sum += query(1, idx[i][0] + 1, idx[i][1] - 1);
        ll lnum = query(1, 1, idx[i][0] - 1) - queryl(1, 1, idx[i][0] - 1) * 2;
        ll rnum = query(1, idx[i][1] + 1, 2 * n) -
                  queryr(1, idx[i][1] + 1, 2 * n) * 2;
        sum += lnum + rnum;
        insert(1, idx[i][0]);
        insert(1, idx[i][1]);
        insertl(1, idx[i][1]);
        insertr(1, idx[i][0]);
    }
    while (!ans.empty()) {
        printf("%lld\n", ans.top());
        ans.pop();
    }
    return 0;
}

7-13 A Chinese Idiom

模拟题

Accepted code

#include
using namespace std;

const double pi=acos(-1);

void solve(){
    double r1,r2,d;
    cin>>r1>>r2>>d;
    double d2=-(pow(r2*r2*r2-r1*r1*r1+(r1-d)*(r1-d)*(r1-d),1.0/3.0)-r2);
    printf("%.10lf\n",d2);
}

int main(){
    int t;
    cin>>t;
    while(t--)solve();
    return 0;
}

你可能感兴趣的:(icpc,学习,算法,c++,ACM/ICPC)