思维+LCA

魔卡少女樱CLEAR CARD篇,小樱都上初中了,她说要好好学数学。她有一道作业题是这样的:给你一个数列,要你写出其一个子数列,这个子数列的要求是连续且和最大,如果有多条子数列和一样大就取最前面的一条。
例如,对于数列(-5,6,-1,5,4,-7),就取第2位到第5位这一段,总和为:6 + (-1) + 5 + 4 = 14即是总和最大的一段。

Input输入数据的第一行是一个整数T(1<=T<=20)表示测试实例的个数,然后是T行数据,每一行的开始是一个整数N(1<=N<=100000),然后是N个整数(-1000<=0<=1000).
Output对于每个测试实例,你要输出两行,第一行是"Case #:",#是第#组数据的意思,第二行包含三个整数,最大子数列和,子数列的起始位置,子数列的结束位置。
注意每两组测试样例之间有一个空行。
Sample Input

2
5 6 -1 5 4 -7
7 0 6 -1 1 -6 7 -5

Sample OutputCase 1:

14 1 4

Case 2:
7 1 6

思考这道题目时,需要将数据考虑完全
1)题目所给普通数据
2)当其中遇到断点,对初始位置的定位
3)当所有数据都为负数时例
#include<iostream>
using namespace std;
const int maxn=1e5+10;
int a[maxn];
int main()
{
    int t,n;
    int sum;
    int x=1;
    int st,k;
    cin>>t;
    while(t--)
    { 
        cin>>n;
        for(int i=1;i<=n;i++)
           cin>>a[i];
        int max=-99999;
        int s=1;//开始 
        sum=0;
        for(int i=1;i<=n;i++)
        {
            sum+=a[i];
            if(sum>max)
            {
                max=sum;
                k=i;
                st=s;
            }
            if(sum<0)//若和小于0,说明负值大,舍去这一段,继续重新开始 
            {
                sum=0;
                s=i+1;
            }
        }
        if(x!=1)cout<<endl;
        cout<<"Case "<<x<<":"<<endl;
        cout<<max<<" "<<st<<" "<<k<<endl;
        x++;
    }
    return 0;
}

 B - How far away ?(LCA)

勇气小镇是一个有着n个房屋的小镇,为什么把它叫做勇气小镇呢,这个故事就要从勇气小镇成立的那天说起了,
修建小镇的时候,为了让小镇有特色,镇长特地只修了n-1条路,并且规定说,所有在勇气小镇的村民,每一次出门必须规划好路线,
路线必须满足在到达终点之前绝对不走回头路。每个人都要这样,不然那个人就不配在小镇生活下去,因为他没有这个勇气。
事实上,这并不能算一项挑战,因为n-1条路已经连通了每户人家,不回头地从起点到终点,只是一个时间上的问题。
由于小镇上的福利特别好,所以小懒入住了这个小镇,他规划了m次的行程,每次从L房屋到R房屋,他想问你他每次从L房屋到R房屋最少能走多少路。

Input输入的第一行是一个整数t,表示有t组数据
   每组数据第一行是n,m两个数字,分别表示小镇上房屋的个数,和小懒计划的行程的数量。
之后第2行到第n行,每行三个整数a,b,c表示,a房屋与b房屋之间连接着一条距离为c的小路。
第n+1行到第n+m行,每行两个整数,L,R,代表一次小懒的询问,也就是询问小懒从L房屋走到R房屋所走的最近距离为多少。Output对于每组测试数据输出m行,每行一个整数,代表小懒从询问的L到R需要走的最近的距离Sample Input

2
3 2
1 2 10
3 1 15
1 2
2 3

2 2
1 2 100
1 2
2 1

Sample Output

10
25
100
100

t<=10
2<=n<=40000
1<=m<=200
1<=a<=n
1<=b<=n
1<=c<=40000
1<=L<=n

1<=R<=n

https://blog.csdn.net/nameofcsdn/article/details/52230548 

看了这个题解,总结一下,就是用LCA算法,找最大公共祖先,其中需要根据其特性并且结合rmq算法

#include<iostream>
#include<vector>
using namespace std;
const int maxn=1e5;
struct node
{
    int son;
    int d;
};
 
int n;
vector<node>v[maxn];//存儿子标号
int deep[maxn];//每个点的深度
int visitnum[maxn];//遍历数是2*n-1
int visitn[maxn];//每个点的任意一个遍历数
int num;
int mins[maxn][20];        //区间最小值
int dist[maxn];        //每个点到祖先的距离distance
int fa[maxn];
 
void dfs(int m, int d, int dis)        //遍历重编号、计算distance
{
    vector<node>::iterator p;
    deep[m] = d;
    dist[m] = dis;
    for (p = v[m].begin(); p != v[m].end(); p++)
    {
        if (fa[(*p).son]>-1)continue;
        fa[(*p).son] = m;
        visitnum[num++] = m;    //存入访问的第vnum个点是哪个点
        dfs((*p).son, d + 1, dis + (*p).d);
    }
    visitn[m] = num;        //注意这2句的顺序
    visitnum[num++] = m;
}
 
void rmq()        //计算区间最小值
{
    for (int i = 1; i <= 2 * n - 1; i++)
         mins[i][0] = visitnum[i];
    for (int j = 1; (1 << j) <= 2 * n - 1; j++)
    {
        for (int i = 1; i <= 2 * n - 1; i++)
        {
            mins[i][j] = mins[i][j - 1];
            int k = i + (1 << (j - 1));
            if (k <= 2 * n - 1 && deep[mins[i][j]] > deep[mins[k][j - 1]])
                mins[i][j] = mins[k][j - 1];
        }
    }
}
 
int lca(int x, int y)    //求最近公共祖先
{
    x = visitn[x], y = visitn[y];
    if (x > y)
         x ^= y ^= x ^= y;
    int j = 0;
    while ((1 << j) <= y - x + 1)
          j++;
    j--;
    int min = mins[y + 1 - (1 << j)][j];
    if (deep[min] > deep[mins[x][j]])
        min = mins[x][j];
    return min;
}
 
int main()
{
    int t, m, x, y, l;
    cin >> t;
    while (t--)
    {
        cin >> n >> m;
        num = 1;
        for (int i = 1; i <= n; i++)
        {
            v[i].clear();    //初始化
            fa[i] = -1;
        }
        for (int i = 1; i < n; i++)
        {
            scanf("%d%d%d", &x, &y, &l);
            node nod1, nod2;
            nod1.d = l, nod1.son = y;
            v[x].insert(v[x].end(), nod1);
            nod2.d = l, nod2.son = x;
            v[y].insert(v[y].end(), nod2);
        }
        fa[1] = 1;
        dfs(1, 1, 0);
        rmq();
        while (m--)
        {
            scanf("%d%d", &x, &y);
            printf("%d
", dist[x] + dist[y] - dist[lca(x, y)] * 2);
        }
    }
    return 0;
}

 A - Alice and the List of Presents(思维题)

Alice got many presents these days. So she decided to pack them into boxes and send them to her friends.

There are nn kinds of presents. Presents of one kind are identical (i.e. there is no way to distinguish two gifts of the same kind). Presents of different kinds are different (i.e. that is, two gifts of different kinds are distinguishable). The number of presents of each kind, that Alice has is very big, so we can consider Alice has an infinite number of gifts of each kind.

Also, there are mm boxes. All of them are for different people, so they are pairwise distinct (consider that the names of mm friends are written on the boxes). For example, putting the first kind of present into the first box but not into the second box, is different from putting the first kind of present into the second box but not into the first box.

Alice wants to pack presents with the following rules:

  • She won't pack more than one present of each kind into the same box, so each box should contain presents of different kinds (i.e. each box contains a subset of nn kinds, empty boxes are allowed);
  • For each kind at least one present should be packed into some box.

Now Alice wants to know how many different ways to pack the presents exists. Please, help her and calculate this number. Since the answer can be huge, output it by modulo 109+7109+7.

See examples and their notes for clarification.

Input

The first line contains two integers nn and mm, separated by spaces (1n,m1091≤n,m≤109) — the number of kinds of presents and the number of boxes that Alice has.

Output

Print one integer  — the number of ways to pack the presents with Alice's rules, calculated by modulo 109+7109+7

Examples

Input
1 3
Output
7
Input
2 2
Output
9

Note

In the first example, there are seven ways to pack presents:

{1}{}{}{1}{}{}

{}{1}{}{}{1}{}

{}{}{1}{}{}{1}

{1}{1}{}{1}{1}{}

{}{1}{1}{}{1}{1}

{1}{}{1}{1}{}{1}

{1}{1}{1}{1}{1}{1}

In the second example there are nine ways to pack presents:

{}{1,2}{}{1,2}

{1}{2}{1}{2}

{1}{1,2}{1}{1,2}

{2}{1}{2}{1}

{2}{1,2}{2}{1,2}

{1,2}{}{1,2}{}

{1,2}{1}{1,2}{1}

{1,2}{2}{1,2}{2}

{1,2}{1,2}{1,2}{1,2}

For example, the way {2}{2}{2}{2} is wrong, because presents of the first kind should be used in the least one box.

题解:这道题需要推出公式

m个箱子,根据题意,可以放礼物的方式有2^m种,但是由于她一定有礼物,所以至少有一个箱子里有一种礼物,所以需要减去箱子全空的情况,即2^m-1,一种礼物这样放,n种礼物也是同样的放法,所以公式就是(2^m-1)^n,到这还没结束,因为给的数据大,我们需要考虑一种方法来解决,此时应该就是快速幂了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1e9+7;
ll ksm(ll a,ll b,ll k)
{
    long long ans=1;
    a=a%k;
    while(b>0)
    {
        if(b%2==1)
           ans=(ans*a)%k;
        b/=2;
        a=(a*a)%k;
    }
    return ans;
} 
int main()
{
    ll n,m,a,b;
    scanf("%lld%lld",&n,&m);
    a=ksm(2,m,maxn);
    b=ksm(a-1,n,maxn);
    cout<<b<<endl;
    return 0;
}

B - Factory

我们将A省简化为由N个城市组成,某些城市之间存在双向道路,而且A省的交通有一个特点就是任意两个城市之间都能通过道路相互到达,且在不重复经过城市的情况下任意两个城市之间的到达方案都是唯一的。聪明的你一定已经发现,这些城市构成了树这样一个结构。

现在百度陆续开了许许多多的子公司。每家子公司又会在各城市中不断兴建属于该子公司的办公室。

由于各个子公司之间经常有资源的流动,所以公司员工常常想知道,两家子公司间的最小距离。
我们可以把子公司看成一个由办公室组成的集合。那么两个子公司A和B的最小距离定义为min(dist(x,y))(x∈A,y∈B)。其中dist(x,y)表示两个办公室之间的最短路径长度。

现在共有Q个询问,每次询问分别在两个子公司间的最小距离。

Input第一行一个正整数T,表示数据组数。

对于每组数据:

第一行两个正整数N和M。城市编号为1至N,子公司编号为1至M。

接下来N-1行给定所有道路的两端城市编号和道路长度。

接下来M行,依次按编号顺序给出各子公司办公室所在位置,每行第一个整数G,表示办公室数,接下来G个数为办公室所在位置。

接下来一个整数Q,表示询问数。

接下来Q行,每行两个正整数a,b(a不等于b),表示询问的两个子公司。


【数据范围】

0<=边权<=100

1<=N,M,Q,工厂总数<=100000Output对于每个询问,输出一行,表示答案。Sample Input

1
3 3
1 2 1
2 3 1
2 1 1
2 2 3
2 1 3
3
1 2
2 3
1 3

Sample Output

1
0
0


原文地址:https://www.cnblogs.com/ylrwj/p/11692894.html