2019 ICPC 南昌站 CEGL (持续更新)

C

Description

Given an extremely large non-negative integer n n n, you are asked to count the number of pairs ( i , j ) (i,j) (i,j) of integers satisfying the following conditions:

  • 0 ≤ j ≤ i ≤ n 0\leq j\leq i\leq n 0jin;
  • i & n = i i \& n=i i&n=i; and
  • i & j = 0 i \& j=0 i&j=0.

Here & represents the bitwise AND operator.

For simplicity, the binary representation of n n n will be given. Meanwhile, you only need to output the answer modulo ( 1 0 9 + 7 ) (10^9+7) (109+7).

Input

The first line contains an integer T   ( 1 ≤ T ≤ 20 ) T~(1\le T\le 20) T (1T20) indicating the number of test cases.

Each of the following T T T lines contains a string S   ( 1 ≤ ∣ S ∣ ≤ 1 0 5 ) S~(1 \le |S| \le 10^5) S (1S105) which is the binary representation of the non-negative integer n n n. Note that leading zeros of S S S could appear in the input.

Output

For each test case, output a line containing the answer described above modulo ( 1 0 9 + 7 ) (10^9+7) (109+7).

Solution

1.显然,(0, 0)也是一对解,因此答案至少为1。

2.遍历方向。

由于 n n n以二进制的形式表现,而找的 ( i , j ) (i, j) (i,j)对又要求 j ≤ i j\leq i ji ,若选择遍历 i i i去寻找 j j j的答案,需要找到比 i i i小的区间中寻找答案,因此可以从 n n n的二进制串从地位到高位去遍历,就相当于 i i i从小到大遍历,也方便记录信息。

通过这种方法,在遍历的时候,记录0和1的个数,为找答案对做好准备。

3.判定答案。

该题解的判定方式是:当n的二进制位为1时,进行判定。

判定方式:观察该位后面的0和1的数量,讨论对答案的贡献。

先打个表,方便理解:

0 & 0 = 0 0\&0=0 0&0=0, 0 & 1 = 0 0\&1=0 0&1=0, 1 & 0 = 0 1\&0=0 1&0=0, 1 & 1 = 1 1\&1=1 1&1=1.

  1. 该位后面为0

由于有限定条件: i & n = i i\&n=i i&n=i,由于 n n n的该位为 0 0 0,由表得, i i i只能取 0 0 0

又有限定条件: i & j = 0 i\&j=0 i&j=0,此时 i i i 0 0 0 j j j可以取 0 0 0 1 1 1,此时贡献两个对的答案 ( 0 , 0 ) , ( 0 , 1 ) (0,0), (0,1) (0,0),(0,1).

  1. 该位后面为1

由于有限定条件: i & n = i i\&n=i i&n=i,由于 n n n的该位为 1 1 1,由表得, i i i可取 0 0 0 1 1 1

又有限定条件: i & j = 0 i\&j=0 i&j=0,此时 i i i 0 0 0 1 1 1 j j j可以取 0 0 0 1 1 1,此时贡献三个对的答案 ( 0 , 0 ) , ( 0 , 1 ) , ( 1 , 0 ) (0,0), (0,1), (1,0) (0,0),(0,1),(1,0).

此时,由于我们遍历到n的二进制位为1才进行答案的更新,答案的统计不包括这位,于是可以保证满足 j ≤ i j\leq i ji

4.计算答案贡献。

由上面的分析得,当n的二进制位为0时有2种组合,为1时有3种组合。

令此前统计的0的个数为num0,1的个数为num1;

对答案的贡献为 2 n u m 0 ∗ 3 n u m 1 2^{num0}*3^{num1} 2num03num1

记得取余。

Code

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

#define MOD 1000000007
#define intmax 2147483647
#define memmax 0x7fffffff

ll t;
string s;

ll quickPow(ll n, ll p, ll k)
{
    
    
    ll ans = 1;
    ll base = n;

    while (p)
    {
    
    
        //最后一位为1
        if (p & 1)
        {
    
    
            ans *= base;
            ans %= k;
        }
        //去掉一位数
        base *= base;
        base %= k;
        p >>= 1;
    }

    return ans;
}

void solve()
{
    
    
    cin >> s;

    ll ans = 0;
    ans++;// add (0, 0)

    ll num0 = 0, num1 = 0;
    for (int i = s.length() - 1; i >= 0; i--)
    {
    
    
        // i&n == i
        
        // i&j == 0
        if (s[i] == '1')
        {
    
    
            ans = (ans + quickPow(2, num0, MOD) * quickPow(3, num1, MOD)) % MOD;

            num1++;
        }
        else
        {
    
    
            num0++;
        }
    }

    cout << ans << endl;
}

int main()
{
    
    
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> t;
    for (int i = 1; i <= t; i++)
    {
    
    
        solve();
    }
}

E

Description

Bob was in trouble.He rubbed the magic ring on his finger, and you came out of the ground.

You are given an undirected graph G G G which contains n n n vertices labelled from 1 1 1 to n n n, with m m m weighted edges between them coloured in black or white. You have to choose some edges in G G G such that there is at least one path between any two vertices only passing by selected edges, and you can select no more than k k k white edges. There may be multiple available strategies to determine these edges, and you are asked to find out the way with a maximum total weight of edges.

Input

The first line contains an integer T ( 1 ≤ T ≤ 5 ) T (1\leq T\leq 5) T(1T5) indicating the number of test cases.

For each test case, the first line contains three integers n   ( 1 ≤ n ≤ 50000 ) n~(1 \le n \le 50000) n (1n50000), m m m and k   ( 1 ≤ k ≤ m ≤ 500000 ) k~(1\le k\le m \le 500000) k (1km500000).

Each of the following m m m lines contains four integers u , v   ( 1 ≤ u , v ≤ n ) , w   ( 0 ≤ w ≤ 100000 ) u, v~(1\le u,v\le n), w~(0\le w\le 100000) u,v (1u,vn),w (0w100000) and c   ( 0 ≤ c ≤ 1 ) c~(0\le c\le 1) c (0c1) describing an edge of weight w w w and colour c c c between the u u u-th vertex and the v v v-th vertex. Here an edge is white if c = 1 c = 1 c=1, or black if c = 0 c = 0 c=0.

Note that there may be multiple edges between some vertices, and self-loops are also allowed.

Output

For each test case, output a single line with an integer indicating the maximum total weight of selected edges, or output − 1 -1 1 if there is no solution for the given graph.

Solution

1.由题目中at least one path between any two vertices only passing by selected edges可以得出,至少需要构造生成树。

2.题目求最大权值。

由于题目对黑边没有任何限制,基于贪心,黑边有得加就加;

白边不能超过 k k k条,在此基础上继续跑最大生成树即可。

加的白边到了 k k k条就判是否连通。

最后如果加不到 k k k条也要判一次联通。

此处生成树用 K r u s k a l Kruskal Kruskal算法。

3.细节

优先让图联通,图联通了,白边不够 k k k条,也尽量把白边加入权值里去。

Code

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

#define MOD 1000000007
#define intmax 2147483647
#define memmax 0x7fffffff

ll t;
ll n, m, k;
ll u, v, w, iswhite;

ll ans, times;// 总权值,联通点
ll fa[50005];
bool vis[500005];
struct node
{
    
    
    ll u, v, w, iswhite;

} graph[500005];

//图的边按照边权值从大到小排序
bool cmp(node a, node b)
{
    
    
    return a.w > b.w;
}

//并查集查找思想
ll find(ll x)
{
    
    
    if (fa[x] != x)
        return fa[x] = find(fa[x]);
    return fa[x];
}

void Kruskal()
{
    
    

    // 将黑边全部加入树中
    for (int i = 1; i <= m; i++)
    {
    
    
        if (!graph[i].iswhite)
        {
    
    
            // 此处不用考虑联通才加权值
            // 黑的直接加入到答案中
            ans += graph[i].w;

            ll ru = find(graph[i].u);
            ll rv = find(graph[i].v);

            //还没连在一起
            //加入树里
            //答案加权值
            if (ru != rv)
            {
    
    
                fa[ru] = rv;
                times++;
            }
        }
    }

    ll numwhite = 0;

    //从大到小加入边
    for (int i = 1; i <= m; i++)
    {
    
    
        if (graph[i].iswhite)
        {
    
    

            ll ru = find(graph[i].u);
            ll rv = find(graph[i].v);

            //还没连在一起
            //加入树里
            //答案加权值
            if (ru != rv)
            {
    
    
                fa[ru] = rv;
                times++;
                numwhite++;
                ans += graph[i].w;
				//记录该边用过
                vis[i] = true;
                // 白边加满了
                if (numwhite >= k)
                {
    
    
                    if (times == n - 1)
                    {
    
    
                        cout << ans << endl;
                        return;
                    }
                    else
                    {
    
    
                        cout << -1 << endl;
                        return;
                    }
                }
            }
        }
    }
	
    //白边不够k条,尽量把边加进答案
    for (int i = 1; i <= m; i++)
    {
    
    
        if (!vis[i] && graph[i].iswhite && numwhite < k)
        {
    
    
            numwhite++;
            ans += graph[i].w;

            if (numwhite >= k)
            {
    
    
                if (times == n - 1)
                {
    
    
                    cout << ans << endl;
                    return;
                }
                else
                {
    
    
                    cout << -1 << endl;
                    return;
                }
            }
        }
    }

    if (times == n - 1)
        cout << ans << endl;
    else
        cout << -1 << endl;
}

void solve()
{
    
    
    ans = 0;
    times = 0;

    cin >> n >> m >> k;

    //并查集初始化祖先
    for (int i = 1; i <= n; i++)
        fa[i] = i;
    //读入边权
    for (int i = 1; i <= m; i++)
    {
    
    
        vis[i] = false;
        cin >> u >> v >> w >> iswhite;

        graph[i].u = u;
        graph[i].v = v;
        graph[i].w = w;
        graph[i].iswhite = iswhite;
    }
    //按权值从大到小排序
    sort(graph + 1, graph + m + 1, cmp);

    Kruskal();
}

int main()
{
    
    
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> t;
    while (t--)
        solve();
}

G

Description

Bob is hungry now and he needs to eat some food. Alice puts n n n dishes of food in front of him, numbered from 1 1 1 to n n n. Alice tells him that he can only eat continuous dishes of food, or he will be poisoned by food. For example, if there are 10 10 10 dishes, he can eat the food in the 2 − n d 2-nd 2nd, 3 − r d 3-rd 3rd and 4 − t h 4-th 4th dishes but he can not eat the food in the 2 − n d 2-nd 2nd, 3 − r d 3-rd 3rd and 5 − t h 5-th 5th dishes because there is the 4 − t h 4-th 4th dish between them so it’s not continuous. Furthermore, if he chooses to eat food in the i i i-th dish, he has to eat all food in that dish.

Bob’s stomach has a strange feature that if there is at least t   ( = 998857459 ) t~(=998857459) t (=998857459) kg food in it, the weight in it will reduce t t t kg repeatedly until it is strictly lower than t t t kg. Also, if the weight of food in his stomach is exactly t t t kg, his stomach will be empty. Now Bob wants to eat the smallest number of dishes and remains no less than k k k kg food in his stomach. Can you tell him how many dishes he needs to choose?

Input

The first line contains two integers n n n and m   ( 1 ≤ n ≤ 100000 , 1 ≤ m ≤ 10000 ) m~(1\leq n\leq 100000,1\leq m\leq 10000) m (1n100000,1m10000), indicates the number of dishes and the number of queries.

The second line contains n n n integers a 1 , a 2 , ⋯   , a n a_1,a_2,\cdots,a_n a1,a2,,an, which is a permutation of 1 , 2 , ⋯   , n 1, 2, \cdots, n 1,2,,n, indicates that there is ( a i ! ) (a_i!) (ai!) kg food in the i i i-th dish, where s ! = 1 × 2 × 3 × ⋯ × s s! = 1 \times 2 \times 3 \times \cdots \times s s!=1×2×3××s.

The third line contains m m m integers, the i i i-th integer k i ( 1 ≤ k i < t ) k_i(1\leq k_i<t) ki(1ki<t) indicates a query with the lower bound of weight.

Output

Each line of m m m lines contains an integer indicates the number of dishes Bob needs to choose in that query. If there is no way to reach Bob’s target, output -1 instead.

Solution

1.打表看出,当 n ≥ 2803 n\geq 2803 n2803后的数都为0(与取余数有关),可以用 O ( n 2 ) O(n^2) O(n2)算法预处理。

预处理方法:用前缀和记录值,更新区间最大值即可。

2.细节

可以另开一个结构体存值和下标(用于剔除那些a[i]为0的,对答案没有贡献的)

Code

#include <bits/stdc++.h>

typedef long long ll;

#define MOD 998857459
#define intmax 2147483647
#define memmax 0x7fffffff

using namespace std;

ll n, m;
ll jie[100005];
ll a[100005];
ll k;

// 新的表
struct node
{
    
    
    ll value;
    ll id;
}res[3005];
ll cnt;

ll sum[3005];
ll ans[100005];// 区间内的最大可得到值

void solve()
{
    
    
    
    cin >> k;

    // 贪心找到最小的比k大的区间值
    for(int i=1; i<=n; i++)
    {
    
    
        if(ans[i] >= k)
        {
    
    
            cout << i << endl;
            return ;
        }
    }
    cout << -1 << endl;
    
}

int main(void)
{
    
    
    
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    // 预处理
    jie[0] = 1;
    for(ll i=1; i<=2802; i++)
        jie[i] = jie[i-1]*i%MOD;
    // input
    cin >> n >> m;
    for(int i=1; i<=n; i++)
    {
    
    
        ll tmp;
        cin >> tmp;
        a[i] = jie[tmp];
    }

    // deal
    for(int i=1; i<=n; i++)
    {
    
    
        // 只取有贡献的
        if(a[i])
        {
    
    
            cnt++;
            res[cnt].value = a[i];// 存值
            res[cnt].id = i;//存下标
            // 此处sum不需要取余
            sum[cnt] = sum[cnt-1]+res[cnt].value%MOD;
        }
    }

    // n^2 处理每个区间
    for(int i=1; i<=cnt; i++)
    {
    
    
        for(int j=i; j<=cnt; j++)
        {
    
    
            ll ind = res[j].id - res[i].id + 1;
            ans[ind] = max(ans[ind], (sum[j]-sum[i-1])%MOD);
        }
    }

    while(m--)
        solve();

    return 0;
}

L

Description

Soccer is probably the sport with the greatest fans in this country. However, the national team has a poor record on the world stage. In order to energize youth players, the Soccer National Championship is organized every year.

In this year, there are n n n teams taking part in the championship. As usual, the single round-robin system is adopted so that each team plays every other team once. A standard match askes ten players and a goalkeeper for both teams, which contains 22 players in total. They confront each other, defend their nets and attack the opponent’s goal in a rectangular grass court.

In a 90-minute game, they try to shoot again and again. When the game is over, the team with higher goals will win and obtain 3 3 3 points in the scoreboard, while the loser will obtain nothing. A very special but common case is that both teams get the same goals, which is a draw; then both of them will obtain one point in the scoreboard.

At the end of the season, the league will declare the champion which is the team with the highest score in total. If two or more teams have the same highest score in total, the one with the highest goal differential (which is calculated as the number of goals scored in all league matches minus the number of goals conceded) will be the champion. The worst situation that several teams have the same highest score in total and the same goal differential will be solved by extra play-offs.

Input

The first line contains an integer n   ( 1 ≤ n ≤ 100 ) n~(1\le n \le 100) n (1n100) indicating the number of teams.

Each of the following n n n lines contains n n n integers. The j j j-th integer in the i i i-th line, which is non-negative and up to five, represents the number of goals scored by the i i i-th team against the j j j-th team.

We guarantee that a i , i = 0 a_{i,i}=0 ai,i=0 for all 1 ≤ i ≤ n 1\le i \le n 1in.

Output

If the league can declare the champion, output the index of the team who will be the champion or output play-offs (without quotes), if extra play-offs will be organized.

Solution

1.签到题,模拟即可。

特殊情况:n=1时直接输出1即可;

按积分和净胜球排个序,

如果第一第二积分和净胜球一样就play-offs

不然输出第一个的ID即可。

Code

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

#define MOD 1000000007
#define intmax 2147483647
#define memmax 0x7fffffff

ll n;
struct node
{
    
    
    ll ind;
    ll score;
    ll ball;
} arr[105];
ll a[105][105];

bool cmp(node a, node b)
{
    
    
    if (a.score != b.score)
        return a.score > b.score;
    return a.ball > b.ball;
}

void solve()
{
    
    
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++)
    {
    
    
        arr[i].ind = i;
        for (int j = 1; j <= n; j++)
            scanf("%lld", &a[i][j]);
    }

    if (n == 1)
    {
    
    
        printf("%lld\n", arr[1].ind);
        return;
    }

    for (int i = 1; i <= n; i++)
    {
    
    
        for (int j = 1; j <= n; j++)
        {
    
    
            // 自身忽略
            if (i == j)
                continue;

            // 统计得分
            if (a[i][j] > a[j][i])
                arr[i].score += 3;
            else if (a[i][j] == a[j][i])
                arr[i].score++;
			// 统计净胜球
            arr[i].ball += a[i][j] - a[j][i];
        }
    }

    sort(arr + 1, arr + n + 1, cmp);

    if (arr[1].score == arr[2].score && arr[1].ball == arr[2].ball)
        printf("play-offs\n");
    else
        printf("%lld\n", arr[1].ind);
}

int main()
{
    
    
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    solve();
}

猜你喜欢

转载自blog.csdn.net/weixin_45812280/article/details/121424928