【瓜分5000元奖金】Wannafly挑战赛13题目题解

A-zzy的小号

/*****************************
Author Ms. Wen
Date 2018/4/6

解题思路:
i,l,I,L   等价  遇到任意一个*4
o,O,0     等价  遇到任意一个*3
大小写字母等价  遇到任意一个*2
*******************************/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

const int mod = 1e9+7;
char str[1000000];
int main() {
    while(~scanf("%s",str)) {
        long long ans = 1;
        for(int i = 0; i < (int)strlen(str); i++) {
            if(str[i]>='a' && str[i]<='z') {
                if(str[i]=='l' || str[i]=='i') {
                    ans = ans*4%mod;
                }
                else if(str[i]=='o') {
                    ans = ans*3%mod;
                }
                else {
                    ans = ans*2%mod;
                }
            }
            else if(str[i]>='A'&&str[i]<='Z') {
                if(str[i]=='I' || str[i]=='L') {
                    ans = ans*4%mod;
                }
                else if(str[i]=='O') {
                    ans = ans*3%mod;
                }
                else {
                    ans = ans*2%mod;
                }
            }
            else if(str[i] == '0'&&str[i]<='9') {
                ans = ans*3%mod;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

B-Jxc的军训

/*****************************
Author Ms. Wen
Date 2018/4/6

解题思路:
逆向思维,被晒到的概率等于1-不被晒到的概率。
只要站在云下不管太阳在哪都不会被晒到。则
不被云晒到的概率为 m/(n*n)。则被晒到的概率是
(n*n-m)/(n*n)。然后剩余的就是求乘法逆元的事情
了,由于取模的数为素数,因此分母fm的乘法逆元
就是fm^(mod-2)。在题目中我们经常看到概率的答案
很大,其实就是因为这些概率通常牵涉取模,与乘法
逆元有关,不必大惊小怪。
*******************************/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <cmath>

using namespace std;

const int mod = 998244353;

long long qucik(int n,int k) {
    long long ans,res;
    ans = 1;
    res = (long long)n;
    while(k) {
        if(k&1) {
            ans = ans*res%mod;
        }
        res = res*res%mod;
        k = k/2;
    }
    return ans;
}
int main() {
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        int fz = (n*n-m)%mod;
        int fm = (n*n)%mod;
        long long ans = fz*qucik(fm,mod-2)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

C-zzf的好矩阵

/*****************************
Author Ms. Wen
Date 2018/4/6

解题思路:
比如3*3的矩阵,可以通过一定操作放成
1 2 3
4 5 6
7 8 9
由于矩阵中的数字大于0且小于等于n*n,且各个
位置上数不同。则矩阵中的数字必是1~n*n中的数字
各一个。经过烟草发现。1 4 7,2 3 8,3 6 9 .
必是一列。1 2 3,4 5 6,7 8 9,必是一列,因此只要
固定1,2,3的位置,与其绑定的数字必绑定。
1 ,2 ,3的排列数都3!种。横排的数还可以挑选自己
所处的行,又是3!种。而上例中所有在一行的可以换
成在一列。
1 4 7
2 5 8
3 6 9
因此n*n的矩阵,总共有n!*n!*2种放置方法。
*******************************/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <cmath>

using namespace std;

const int mod = 998244353;
typedef long long ll;
int main() {
    int p;
    while(~scanf("%d",&p)) {
        ll ans = 1;
        for(ll i = 1; i <= p; i++) {
            ans = ans*i%mod;
        }
        ans = ans*ans%mod;
        ans = ans*2%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

D-applese的生日

/***************************************************************
Author Ms. Wen
Date 2018/4/6

思路:题解上说得挺清楚。
首先有一个结论:每块蛋糕分成的每一块的大小是相同的 基于这个结论,
每次找到当前划分最大块所在的大块并将其划分数+1,检查是否满足题目的
要求考虑这个结论为什么是正确的考虑一个蛋糕切的刀数不变,那么可以想
到假如分割得到的块是不同的,那么可能的贡 献是增加最大和最小之间的差
值,那么这样答案只会更劣,所以可以想到分成的每个块的大小是相同的。
*******************************************************************/
#include <iostream>
#include <stdio.h>
#include <map>

using namespace std;

const int maxn = 1005;
double w[maxn];
int divs[maxn];  //蛋糕的分块数。
multimap<double,int>m; //multimap中key的值可以重复
multimap<double,int>::iterator it1,it2;
int main() {
    double t;
    int n;
    cin>>t>>n;
    m.clear();
    for(int i = 1; i <= n; i++) {
        cin>>w[i];
        divs[i] = 1;
        m.insert(make_pair(w[i],i));
    }
    it1 = m.begin();
    it2 = --m.end();
    int ans = 0;
    while(it1->first/it2->first < t) {
        int id = it2->second;
        divs[id]++;
        double aver = w[id]/divs[id];
        m.erase(it2);
        m.insert(make_pair(aver,id));
        it1 = m.begin();
        it2 = --m.end();
        ans++;
    }
    printf("%d\n",ans);
    return 0;
}

E-VVQ与线段

/**************************************
Author Ms. Wen
Date 2018/4/7

解题思路:
对于所有线段按照左端点从小到大排序。
对于一条选定的线段x1,y1。需要考虑左端点大于等于x1且小于等于y1的
所有线段x2,y2
1.考虑Seg(x2,y2)与Seg(x1,y1)相交但不包含在Seg(x1,y1)中,则异或值
为(x2+y2)-(x1+y1).由于x1+y1固定,则需要使x2+y2最大。因此建立线段
树维护所有线段left+right的最大值。
2.考虑Seg(x2,y2)包含在Seg(x1,y1)中,则异或值为(y1-x1)-(y2-x2)。
由于y1-x1固定,则需要使y2-x2最小,因此建立线段树维护所有线段right-left
的最小值。
求这两种情况的最大值。即为答案。

变量含义:
Max:维护线段left+right最大值的数组
Min:维护线段right-left最小值的数组
s:存放线段信息

方法含义:
push_up1(root):用于更新Max数组的值
push_up2(root):用于更新Min数组的值
build1:构造维护left+right的线段树
build2:构造维护right-left的线段树
query1:求与当前线段相交的线段中left+right值最大的。
query2:求与包含在当前线段中的线段中right-left值最小的。
**********************************************************/
#include <iostream>
#include <stdio.h>
#include <algorithm>
#define lchild left,mid,root<<1
#define rchild mid+1,right,root<<1|1

using namespace std;

const int maxn = 200000+4;
int Max[maxn<<2];   //维护线段l+r的最大值
int Min[maxn<<2];   //维护线段r-l的最小值
struct Segment {
    int left;
    int right;
    friend bool operator<(Segment s1,Segment s2) {
        return s1.left<s2.left;
    }
}s[maxn];
void push_up1(int root) {
    Max[root] = max(Max[root<<1],Max[root<<1|1]);
}
void push_up2(int root) {
    Min[root] = min(Min[root<<1],Min[root<<1|1]);
}
//维护l+r的最大值,处理相交情况
void build1(int left,int right,int root) {
    if(left==right) {
        Max[root] = s[left].left + s[left].right;
        return;
    }
    int mid = (left+right)>>1;
    build1(lchild);  //递归构建左右子树
    build1(rchild);
    push_up1(root);
}
//维护r-l的最小值,处理包含的情况
void build2(int left,int right,int root){
    if(left==right) {
        Min[root] = s[left].right - s[left].left;
        return;
    }
    int mid = (left+right)>>1;
    build2(lchild);
    build2(rchild);
    push_up2(root);
}
int query1(int L,int R,int left,int right,int root) {
    if(L<=left && right<=R) {
        return Max[root];
    }
    int mid = (left+right)>>1;
    int ans = 0;
    if(L<=mid) ans = max(ans,query1(L,R,lchild));
    if(R>mid) ans = max(ans,query1(L,R,rchild));
    return ans;
}
int query2(int L,int R,int left,int right,int root) {
    if(L<=left && right<=R) {
        return Min[root];
    }
    int mid = (left+right)>>1;
    int ans = 1e8;
    if(L<=mid) ans = min(ans,query2(L,R,lchild));
    if(R>mid)  ans = min(ans,query2(L,R,rchild));
    return ans;
}
int main() {
    int n,l,r;
    while(~scanf("%d",&n)) {
        for(int i = 1; i <= n; i++) {
            scanf("%d%d",&l,&r);
            s[i].left = min(l,r);  //防止有l>r的坑
            s[i].right = max(l,r);
        }
        sort(s+1,s+n+1);  //按照左端点,从小到大排序。
        build1(1,n,1);
        build2(1,n,1);
        Segment tmp;
        tmp.right = 0;
        int ans = 0;
        for(int i = 1; i <= n; i++) {
            tmp.left = s[i].left;
            l = lower_bound(s+1,s+n+1,tmp)-s;   //寻找左端点>=当前线段的第一条线段
            tmp.left = s[i].right;
            r = upper_bound(s+1,s+n+1,tmp)-s-1; //寻找左端点>当前右端点的第一条线段。
            if(l > r) continue;
            //则下标(l,r)内的线段都与当前线段相交或被包含其中。
            int num1 = query1(l,r,1,n,1);
            int num2 = query2(l,r,1,n,1);
            ans = max(ans,num1-(s[i].left+s[i].right));
            ans = max(ans,(s[i].right-s[i].left)-num2);
        }
        printf("%d\n",ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值