FJUT2019暑假第二次周赛题解

A 服务器维护

题目大意:

  给出时间段[S,E],这段时间需要人维护服务器,给出n个小时间段[ai,bi],代表每个人会维护的时间段,每个人维护这段时间有一个花费,现在问题就是维护服务器[S,E]这段时间,需要最小花费是多少,就是用n个小时间段[ai,bi],覆盖满[S,E]这段时间并且所用的花费最少。

解题思路:

  解法一:最短路径,这是我一开始想到的用的算法,S到E需要使用最小花费,并且还给出每一小段的路程和花费,感觉就像最短路径裸题吖,但是这题问题在于如何建图,如果你使用常规方法建图是不可行的,因为最短路径是覆盖边,而这题给出的是需要覆盖点,假设[2,4] 我们需要覆盖点2,3,4三个点,而一般最短路径建图[2,4]是覆盖2->3,3->4两条边,我们就少一个覆盖的权,所以我们就把终点+1,[2,4]转换成[2,5],2->3,3->4,4->5,对应了2,3,4三个点,在建图时,假如给定区间[2,3] 覆盖点2,3对应边为2->3,3->4,我们就建一条从2->4的边,对于给定[ai,bi]建一条ai->bi+1的边。还有一个问题就是关于区间重复的覆盖,例如区间[2,5]和区间[3,6],可以覆盖区间[2,6],如果只按照上面建图是无法连通[2,6]的,所以我们需要给每一个点加一个反向边,就是从点i+1 ->点i且权值为0,这样当通过2->5走到5时我们无法走其他点就可以往回走,走到3,再走3->6这条边。

  解法二:线段树,做完以后发现就我用了最短路,很多大佬用的都是线段树,我太菜了数据结构没学好,没想到,挖坑待补。。。。

代码实现:

dijkstra解法:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cctype>
#include <cstring>
#include <cmath>
#include <iostream>
#include <sstream>
#include <string>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <functional>
#define lowbit(x) (x&(-x))
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define debug(x) cout << #x << ": " << x << endl
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int    prime = 999983;
const int    INF = 0x7FFFFFFF;
const LL     INFF =0x7FFFFFFFFFFFFFFF;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
const LL     mod = 1e9 + 7;
const int    maxn = 1e6 + 7;
const int    maxm = 4e6 + 7;

int n, m, first[maxn], sign;

struct Edge{
    int to, w, next;
}edge[maxn * 2];

void init(){
    for(int i = 0; i <= n; i++){
        first[i] = -1;
    }
    sign = 0;
}

void addEdge(int u,int v,int w){
    edge[sign].to = v;
    edge[sign].w = w;
    edge[sign].next = first[u];
    first[u] = sign++;
}

struct Node{
    int to;
    LL cost;
    Node(){}
    Node(int tt, LL cc):to(tt),cost(cc){}
    friend bool operator < (const Node &a, const Node &b){
        return a.cost > b.cost;
    }
};

LL dist[maxn];
int vis[maxn];

LL dijkstra(int s, int t){
    for(int i = 0; i <= n; i++){
        dist[i] = INFF;
        vis[i] = 0;
    }
    priority_queue<Node> que;
    que.push(Node(s,0));
    while(!que.empty())
    {
        Node now = que.top();
        //printf("%d\n",now.to);
        que.pop();
        if(!vis[now.to]){
            vis[now.to] = 1;
            dist[now.to] = now.cost;
            for(int i = first[now.to];~i;i = edge[i].next){
                int to = edge[i].to;
                LL w = edge[i].w;
                if(!vis[to]){
                    que.push(Node(to,now.cost + w));
                }
            }
        }
    }
    return dist[t] == INFF ? -1 : dist[t];
}
int main()
{
        int s, t;
        scanf("%d%d%d",&m,&s,&t);
        n = t + 1;
        init();
        for(int i = 1; i<= m; i++){
           int u, v, w;
           scanf("%d%d%d",&u,&v,&w);
           addEdge(u,v + 1,w);
        }
        for(int i = s + 1; i <= n; i++){
            addEdge(i ,i - 1, 0);
        }
        printf("%lld\n",dijkstra(s, t+1));
    return 0;
}
View Code

线段树解法:

/*待补。。。。*/
View Code

B CWL的女朋友2

题目大意:

  题意就是给你一个长度为n的字符串,仅仅包含数组1~9,问你能否拆分成几个部分让他们的和相等,例如:178035可以拆分成三个部分1 + 7 = 8 = 0 + 3 + 5。

解题思路:

  数据范围都很小直接暴力模拟就行,分段的数字和一定能被所有数字总和整除,所以分解总和的因子暴力枚举每一个因子看是否能分解出几段数字都和他相等,(tip:总和本身也是自己因子,但是不可行,因为这样他就只有自己本身一段了,不符合题意)

代码实现:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cctype>
#include <cstring>
#include <cmath>
#include <iostream>
#include <sstream>
#include <string>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <functional>
#define lowbit(x) (x&(-x))
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define debug(x) cout << #x << ": " << x << endl
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int    prime = 999983;
const int    INF = 0x7FFFFFFF;
const LL     INFF =0x7FFFFFFFFFFFFFFF;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
const LL     mod = 1e9 + 7;
const int    maxn = 1e7 + 7;
const int    maxm = 4e6 + 7;

int arr[500];
char str[500];
vector<int> vec;

void fj(int x){
    for(int i = 2; i * i <= x; i++){
        if(x % i ==0){
            vec.push_back(i);
            if(x / i != i)
            vec.push_back(x/i);
        }
    }
}

int main()
{
    int n;
    int sum, cnt;
    while(~scanf("%d",&n)){
        getchar();
        sum = 0;
        scanf("%s",str);
        for(int i = 0; i < n; i++){
            arr[i] = str[i] - '0';
            sum += arr[i];
        }
        vec.push_back(1);
        fj(sum);
        bool f,fa = false;
        for(auto val : vec){
            cnt = 0;
            for(int i = 0;i < n ;i ++){
                cnt += arr[i];
                if(cnt == val){
                    cnt = 0;
                }
            }
            if(cnt == 0){
                fa = true;
               break;
            }
        }
        fa ? puts("YES") : puts("NO");
        vec.clear();
    }
}
View Code

C Hang的闯关

题目大意:

  给你前12层每一层Hang身上有的数字,并且告诉你没到一层就会获得一定的0和1(具体多少需要自己猜规律),然后某个数字达到一定数量就会合成,现在告诉你n让你计算Hang身上的数字是多少。

解题思路:

  规律通过关材可以很快的发现奇数层获得0,偶数层获得1和0,两个0合成一个1,三个1合成一个2,四个2合成一个3,我的做法是把0全部转换成1,再看1能够合成的数字,一个2需要3个1,一个3需要12个1,一个4需要60个1,规律3*4....*9,因为最多可以合成的数字只有9(n <= 1e7),我们只要遍历从9开始看1的数量能组成几个9,几个8,直接输出就行。

代码实现:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cctype>
#include <cstring>
#include <cmath>
#include <iostream>
#include <sstream>
#include <string>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <functional>
#define lowbit(x) (x&(-x))
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define debug(x) cout << #x << ": " << x << endl
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int    prime = 999983;
const int    INF = 0x7FFFFFFF;
const LL     INFF =0x7FFFFFFFFFFFFFFF;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
const LL     mod = 1e9 + 7;
const int    maxn = 1e7 + 7;
const int    maxm = 4e6 + 7;

int arr[50];
int vis[20];
int main()
{
    int cnt = 2,t ,n;
    arr[1] = 1;
    for(int i = 3; i <= 11; i++){
        arr[cnt] = arr[cnt - 1] * i;
        cnt ++;
    }
    scanf("%d",&t);
    int num0,num1;
    while(t--){
        scanf("%d",&n);
        num0 = n;
        num1 = n/2;
        num1 += num0/2;
        num0 %= 2;
        memset(vis,0,sizeof(vis));
//        debug(num1);
//        debug(num0);
        for(int i = 9; i>=1 ;i--){
            if(num1 / arr[i]!= 0){
                vis[i] = num1/arr[i];
                num1 %= arr[i];
            }
        }

        for(int i = 9; i >=1 ;i--){
            while(vis[i]){
                printf("%d",i);
                vis[i]--;
            }
        }
        if(num0) puts("0"); else puts("");
    }
    return 0;
}
View Code

D/E 这不傻逼题吗(Easy)/(Hard)

题目大意:

  给你n个选择题,每个题a[i]个选项,在保证每一个题都选对的情况下,如果所有答案往后错填一位,第n位移动到第一位,请你计算做对题目的期望。

解题思路:

  这题我一开始是没想法的(太菜了)队友都秒A的,我D先写了个暴力全排列去计算期望(暴力大法好),然后E题想了挺久,我们考虑先考虑做对第i到题的概率,如果a[i - 1] > a[i] 那个大于a[i]的的部分是不可能是正确答案的,如果a[i - 1] < a[i]那个a[i - 1]部分全部都可能是正确答案,所以a[i]可能做对部分只有min(a[i],a[i-1]),而总的可以能性有a[i] * a[i-1]种,即使p(i) = min(a[i],a[i-1]) / (a[i] * a[i-1]) 做对每一题的权值为1,我们可以直接for一遍把所有题的的期望相加就可以了。(做完后发现min(a[i],a[i-1]) / (a[i] * a[i-1]) 可以化简为 1.0/max(a[i],a[i-1]) )

代码实现:

全排列暴力:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cctype>
#include <cstring>
#include <cmath>
#include <iostream>
#include <sstream>
#include <string>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <functional>
#define lowbit(x) (x&(-x))
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define debug(x) cout << #x << ": " << x << endl
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int    prime = 999983;
const int    INF = 0x7FFFFFFF;
const LL     INFF =0x7FFFFFFFFFFFFFFF;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
const LL     mod = 1e9 + 7;
const int    maxn = 1e6 + 7;
const int    maxm = 4e6 + 7;

int n, sign = 0;
int arr[15];
int re[15][105];
string str[maxn];
void dfs(int deep,LL ji){
    if(deep > n){
        str[sign++] = to_string(ji);
        return ;
    }
    for(int i = 1; i <= arr[deep]; i++){
        dfs(deep + 1,ji * 10 + i);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i = 1; i <= n; i++){
        scanf("%d",arr+i);
    }
    dfs(1,0LL);
    int cnt, ans;
    double fz = 0.0;
    for(int i = 0; i < sign; i++){
            ans = 0;
        for(int j = 0; j < n; j++){
            cnt = (j + 1) % n;
            if(str[i][j] == str[i][cnt]) ans ++;
        }
        fz += ans;
    }
    printf("%.3f",fz/sign);
}
View Code

正解:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cctype>
#include <cstring>
#include <cmath>
#include <iostream>
#include <sstream>
#include <string>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <functional>
#define lowbit(x) (x&(-x))
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define debug(x) cout << #x << ": " << x << endl
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int    prime = 999983;
const int    INF = 0x7FFFFFFF;
const LL     INFF =0x7FFFFFFFFFFFFFFF;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
const LL     mod = 1e9 + 7;
const int    maxn = 1e6 + 7;
const int    maxm = 4e6 + 7;

long long int a[10000005];
int main()
{
    int n;
    long long A,B,C;
    scanf("%d",&n);
    scanf("%lld%lld%lld%lld",&A,&B,&C,&a[1]);
    for (int i=2; i <= n; i++){
       a[i] = ((long long)a[i-1]*A+B)%100000001;
    }
    for (int i = 1; i <= n; i++){
       a[i] = a[i]%C+1;
    }
    double ans = 0.0;
    for (int i = 2; i <= n; i++){
         ans += double(min(a[i],a[i-1]))/double(a[i]*a[i-1]);
    }
        ans += double(min(a[n],a[1]))/double(a[n]*a[1]);
    printf("%.3f\n",ans);
    return 0;
}
View Code

题目大意:

  

解题思路:

  瞎猜。。。。

  具体证明:https://www.plsseer0qaq.top/index.php/acm/196/?tdsourcetag=s_pctim_aiomsg

代码实现:

print(1)
View Code

 

posted @ 2019-08-09 17:25  Gribouillage  阅读(223)  评论(0编辑  收藏  举报