[校内模拟题4]

“与”

(and.pas/.c/.cpp)时间限制:1s;空间限制 64MB

题目描述:

给你一个长度为 n 的序列 A,请你求出一对 Ai,Aj(1<=i<j<=n)使 Ai“与”Aj 最大

Ps:“与”表示位运算 and,在 c++中表示为&。

输入描述:

第一行为 n。接下来 n 行,一行一个数字表示 Ai。

输出描述:

输出最大的 Ai“与”Aj 的结果。

样例输入:

3

8

10

2

样例输出:

8

样例解释:

8 and 10 = 8

8 and 2 = 0

10 and 2 = 2

数据范围:

20%的数据保证 n<=5000100%的数据保证 n<=3*10^5,0<=Ai<=10^9

——————————————————————————————————————————————————————————————

这道题主要是对二进制性质的一些应用,有体现“正难则反”的思想。20分的暴力是很简单的枚举。然后对于另外80分,我们考虑:“与”是要求同一位均是1,结果才为1。而对于2进制,越高位有1,数字越大。所以我们可以考虑将所给数列的数字看成二进制,从二进制最高位向下枚举,若有大于等于两个数“这一位上为1”,那么最终结果的这一位肯定是1,于是我们就可以将所有“这一位上为1”的数保留下来,剩下的数舍弃;而若有少于两个数“这一位上为1”,则这一位上一定为0

stdcode

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int n,a[300002],d[35],ans;//2^30>1000000000
void init()
{
    scanf("%d",&n);
    int i;
    for(i=1;i<=n;i++) scanf("%d",&a[i]);
}
void find()
{
    int i,j,ct,now=n,t;
    for(i=30;i>=0;i--)
       {ct=0;
        for(j=1;j<=now;j++)
           {if(a[j]&(1<<i)) ct++;}
        if(ct<2) continue;
        t=0; d[i]=1;
        for(j=1;j<=now;j++)
           {if(a[j]&(1<<i)) a[++t]=a[j];}
        now=t;
       }
    for(i=30;i>=0;i--)
       {if(d[i])
           ans=ans^(1<<i);
       }
    printf("%d\n",ans);
}
int main()
{
    freopen("and.in","r",stdin);
    freopen("and.out","w",stdout);
    init(); find();
    return 0;
}

小象涂色

(elephant.pas/.c/.cpp)时间限制:1s,空间限制 128MB

题目描述:

小象喜欢为箱子涂色。小象现在有 c 种颜色,编号为 0~c-1;还有 n 个箱子,编号为1~n,最开始每个箱子的颜色为 1。小象涂色时喜欢遵循灵感:它将箱子按编号排成一排,每次涂色时,它随机选择[L,R]这个区间里的一些箱子(不选看做选 0 个),为之涂上随机一种颜色。若一个颜色为 a 的箱子被涂上 b 色,那么这个箱子的颜色会变成(a*b)modc。请问在 k 次涂色后,所有箱子颜色的编号和期望为多少?

输入描述:

第一行为 T,表示有 T 组测试数据。对于每组数据,第一行为三个整数 n,c,k。接下来 k 行,每行两个整数 Li,Ri,表示第 i 个操作的 L 和 R。

输出描述:

对于每组测试数据,输出所有箱子颜色编号和的期望值,结果保留 9 位小数。

样例输入:

3

3 2 2

2 2

1 3

1 3 1

1 1

5 2 2

3 4

2 4

样例输出:

2.062500000

1.000000000

3.875000000

数据范围:

40%的数据 1 <= T <= 5,1 <= n, k <= 15,2 <= c <= 20

100%的数据满足 1 <= T <= 10,1 <= n, k <= 50,2 <= c <= 100,1 <= Li <= Ri <= n

——————————————————————————————————————————————————————————————

一道有关期望的dp。首先可知每个操作中,一个物品会被染色的概率为1/2,用某种颜色染色的概率为1/c。

40分的方程是用f[i][j][k]表示第i个物品在j次操作次数后颜色变为k的概率,时间复杂度大概是$O(T*N*K*c^2)$

60分要考虑到所有物品具有相似性,即n个物品本质是相同的,所以不用枚举物品f[i][j]表示一个物品操作i次颜色变为j的概率。满足:

$f[i+1][j] += f[i][j]*(\frac{1}{2})$

$f[i+1][(j*b) \mod c] += f[i][j]*[(\frac{1}{2})*(\frac{1}{c})]$

初始值$f[0][1]=1$,答案就是$\sum\limits_{j=0}^{c-1}f[i][j]*j$(i表示该箱子的操作次数。复杂度$O(T*K*c^2)$

然而数组开小了得了60分

code

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

typedef double db;
int T, n, c, k; 
int t[50];
db f[50][100], ans;
//db f[50][50], ans;

inline int read() {
    int num = 0, f = 1; char ch = getchar();
    while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
    while (isdigit(ch)) { num = num * 10 + ch - '0'; ch = getchar(); }
    return num * f;
}

int main() {
    freopen("elephant.in", "r", stdin);
    freopen("elephant.out", "w", stdout);
    T = read();
    while (T -- ) {
        memset(f, 0, sizeof(f));
        memset(t, 0, sizeof(t)); ans = 0;
        n = read(); c = read(); k = read();
        f[0][1] = 1.0;
        f[1][1] += 0.5*f[0][1];
        for (int i = 0; i < c; ++ i)
            f[1][i % c] += f[0][1] * 0.5 / c;
        for (int i = 1; i <= k; ++ i)
            for (int j = 0; j < c; ++ j) {
                f[i + 1][j] += 0.5 * f[i][j];
                for (int k = 0; k < c; ++ k) 
                    f[i + 1][j * k % c] += f[i][j] * 0.5 / c;
            }
        for (int i = 1; i <= k; ++ i) 
            t[read()]++, t[read() + 1]--;
        for (int i = 1; i <= n; ++ i) t[i] += t[i - 1];
        for (int i = 1; i <= n; ++ i)
            for (int j = 0; j < c; ++ j)
                ans += f[t[i]][j] * j;
        printf("%.9lf\n", ans);
    }
    return 0;
}

 

行动!行动!

(move.pas/.c/.cpp)时间限制:1s;空间限制:128MB

题目描述:

大 CX 国的大兵 Jack 接到一项任务:敌方占领了 n 座城市(编号 0~n-1),有些城市之间有双向道路相连。Jack 需要空降在一个城市 S,并徒步沿那些道路移动到 T 城市。虽然Jack 每从一个城市到另一个城市都会受伤流血,但大 CX 国毕竟有着“过硬”的军事实力,它不仅已经算出 Jack 在每条道路上会损失的血量,还给 Jack 提供了 k 个“简易急救包”,一个包可以让 Jack 在一条路上的流血量为 0。Jack 想知道自己最少会流多少血,不过他毕竟是无脑的大兵,需要你的帮助。

输入描述:

第一行有三个整数 n,m,k,分别表示城市数,道路数和急救包个数。第二行有两个整数,S,T。分别表示 Jack 空降到的城市编号和最终要到的城市。接下来有 m 行,每行三个整数 a,b,c,表示城市 a 与城市 b 之间有一条双向道路。

输出描述:

Jack 最少要流的血量。

样例输入:

5 6 10 3

3 4 5

0 1 5

0 2 100

1 2 5

2 4 5

2 4 3

样例输出:

8

数据范围:

对于 30%的数据,2<=n<=50,1<=m<=300,k=0;对于 50%的数据,2<=n<=600,1<=m<=6000,0<=k<=1;对于 100%的数据,2<=n<=10000,1<=m<=50000,0<=k<=10.

 

 ——————————————————————————————————————————————————————————————

 

可以用一个二维的dis数组跑最短路,dis[i][j]表示到达i点,用了j次急救包。用最短路做一个类似于dp的东西.

 

code

#include<cstdio>
#include<cstring>
#include<queue>
#include<deque> 
#include<algorithm>
#include<iostream>
#define mp(x, y) make_pair(x, y)
#define qff q.front().first
#define qfs q.front().second

using namespace std;

typedef pair<int, int> pir;
const int INF = 0x3f3f3f3f;
const int MAXN = 10010;
const int MAXM = 50010;
int head[MAXM * 2], tot;
bool vis[MAXN];
int dis[MAXN][20];
int n, m, k, S, T;

deque<pir >q;

struct Edge {
    int to;
    int nxt;
    int val;
}e[MAXM * 2];

inline int read() {
    int num = 0, f = 1; char ch = getchar();
    while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
    while (isdigit(ch)) { num = num * 10 + ch - '0'; ch = getchar(); }
    return num * f;
}

inline void Add_Edge(int x,int y,int z) {
    e[++tot].to = y; e[tot].val = z; 
    e[tot].nxt = head[x]; head[x] = tot;
}

void pre(int s) {
    for (int i = 1; i <= n; ++ i) 
        for (int j = 0; j <= k; ++ j)
            dis[i][j] = INF;
    for (int i = 0; i <= k; ++ i) dis[s][i] = 0; 
    memset(vis,0,sizeof(vis)); 
}

void SPFA(pir s) {
    q.push_front(s); 
    int xx = s.first, Usee, v;
    vis[xx] = true; 
    pir h;
    while (!q.empty()) {
        h = q.front(); q.pop_front() ;
        xx = h.first; Usee = h.second;
        vis[xx] = false;
        for (int i = head[xx]; i ; i = e[i].nxt) {
            v = e[i].to;
            if (dis[v][Usee] > dis[xx][Usee] + e[i].val) {
                dis[v][Usee] = dis[xx][Usee] + e[i].val;
                if (q.empty() || dis[v][Usee] > dis[qff][qfs]) 
                    q.push_back(mp(v, Usee));
                else q.push_front(mp(v, Usee));
            }
            if (Usee < k && dis[xx][Usee] < dis[v][Usee + 1]) {    
                dis[v][Usee + 1] = dis[xx][Usee];
                if (q.empty() || dis[v][Usee + 1] < dis[qff][qfs]) 
                    q.push_back(mp(v, Usee + 1));
                else q.push_front(mp(v, Usee + 1));
            }
        }
    } 
}
 
int main() {
    n = read(); m = read(); k = read();
    S = read() + 1; T = read() + 1;
    for (int i = 1; i <= m; i++) {
        int a = read() + 1, b = read() + 1, c = read();
        Add_Edge(a, b, c);
        Add_Edge(b, a, c);
    }
    pre(S);
    SPFA(mp(S, 0)); 
    int ans = INF;
    for (int i = 0; i <= k; ++ i) ans = min(ans, dis[T][i]);
    cout << ans << endl;
    return 0;
} 

 

posted @ 2018-08-01 16:01  wakelin  阅读(329)  评论(0编辑  收藏  举报