Codeforces Round #261 (Div. 2)(树状数组,dp,dfs构造序列)

C. Pashmak and Buses

Recently Pashmak has been employed in a transportation company. The company hask buses and has a contract with a school which hasn students. The school planned to take the students tod different places for d days (each day in one place). Each day the company provides all the buses for the trip. Pashmak has to arrange the students in the buses. He wants to arrange the students in a way that no two students become close friends. In his ridiculous idea, two students will become close friends if and only if they are in the same buses for alld days.

Please help Pashmak with his weird idea. Assume that each bus has an unlimited capacity.

Input

The first line of input contains three space-separated integers n, k, d (1 ≤ n, d ≤ 1000; 1 ≤ k ≤ 109).

Output

If there is no valid arrangement just print -1. Otherwise printd lines, in each of them print n integers. The j-th integer of thei-th line shows which bus the j-th student has to take on the i-th day. You can assume that the buses are numbered from1 to k.

Sample test(s)
Input
3 2 2
Output
1 1 2 
1 2 1 
Input
3 2 1
Output
-1
Note

Note that two students become close friends only if they share a bus each day. But the bus they share can differ from day to day.

题意:n个学生,k辆车,d天,要求学生两两之间不能在同一辆车一起d天,问怎么一个安排的方案
思路:对于每个学生而言,在d天的坐车情况,只要不和其他人重复即可,这样进行dfs构造序列,如果能构造出n个不同序列,就是可以的,如果不能就输出-1

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=1010;
int ans[maxn][maxn],tmp[maxn];
int n,k,d,cnt;
void dfs(int x)
{
    if(cnt>n)return;
    if(x>d)
    {
        for(int i=1;i<=d;i++)
            ans[i][cnt]=tmp[i];
        cnt++;
        return ;
    }
    for(int i=1;i<=min(k,1000);i++)
    {
        tmp[x]=i;
        dfs(x+1);
    }
}
int main()
{
    while(scanf("%d%d%d",&n,&k,&d)!=EOF)
    {
        memset(ans,0,sizeof(ans));
        cnt=1;
        dfs(1);
        if(cnt<=n)printf("-1\n");
        else
        {
            for(int i=1;i<=d;i++)
            {
                for(int j=1;j<=n;j++)
                    printf("%d ",ans[i][j]);
                printf("\n");
            }
        }
    }
    return 0;
}

D. Pashmak and Parmida's problem

Parmida is a clever girl and she wants to participate in Olympiads this year. Of course she wants her partner to be clever too (although he's not)! Parmida has prepared the following test problem for Pashmak.

There is a sequence a that consists of n integers a1, a2, ..., an. Let's denotef(l, r, x) the number of indicesk such that: l ≤ k ≤ r andak = x. His task is to calculate the number of pairs of indiciesi, j (1 ≤ i < j ≤ n) such thatf(1, i, ai) > f(j, n, aj).

Help Pashmak with the test.

Input

The first line of the input contains an integer n(1 ≤ n ≤ 106). The second line containsn space-separated integers a1, a2, ..., an(1 ≤ ai ≤ 109).

Output

Print a single integer — the answer to the problem.

Sample test(s)
Input
7
1 2 1 1 2 2 1
Output
8
Input
3
1 1 1
Output
1
Input
5
1 2 3 4 5
Output
0
思路:先预处理出f(1,i,ai),f(j,n,aj),然后就是求s1[i]>s[j]&&i<j的和,这个就跟求逆序数是一样的,树状数组就可以了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=1000010;
typedef long long LL;
int n,a[maxn],cnt1[maxn],cnt2[maxn];
map<int,int> m;
struct BIT
{
    int sum[maxn];
    void clear(){memset(sum,0,sizeof(sum));};
    int lowbit(int x){return x&(-x);}
    void update(int x,int val)
    {
        while(x<=n)
        {
            sum[x]+=val;
            x+=lowbit(x);
        }
    }
    int getsum(int x)
    {
        int ans=0;
        while(x>0)
        {
            ans+=sum[x];
            x-=lowbit(x);
        }
        return ans;
    }

}tree;
void solve()
{
    LL ans=0;
    tree.clear();
    for(int i=n;i>=1;i--)
    {
        ans+=tree.getsum(max(cnt1[i]-1,0));
        if(cnt2[i])tree.update(cnt2[i],1);
    }
    cout<<ans<<endl;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        m[a[i]]++;
        cnt1[i]=m[a[i]];
    }
    m.clear();
    for(int i=n;i>0;i--)
    {
        m[a[i]]++;
        cnt2[i]=m[a[i]];
    }
    solve();
    return 0;
}

E. Pashmak and Graph

Pashmak's homework is a problem about graphs. Although he always tries to do his homework completely, he can't solve this problem. As you know, he's really weak at graph theory; so try to help him in solving the problem.

You are given a weighted directed graph with n vertices and m edges. You need to find a path (perhaps, non-simple) with maximum number of edges, such that the weights of the edges increase along the path. In other words, each edge of the path must have strictly greater weight than the previous edge in the path.

Help Pashmak, print the number of edges in the required path.

Input

The first line contains two integers n, m (2 ≤ n ≤ 3·105; 1 ≤ m ≤ min(n·(n - 1), 3·105)). Then, m lines follows. The i-th line contains three space separated integers: ui, vi, wi (1 ≤ ui, vi ≤ n; 1 ≤ wi ≤ 105) which indicates that there's a directed edge with weight wi from vertex ui to vertex vi.

It's guaranteed that the graph doesn't contain self-loops and multiple edges.

Output

Print a single integer — the answer to the problem.

Sample test(s)
Input
3 3
1 2 1
2 3 1
3 1 1
Output
1
Input
3 3
1 2 1
2 3 2
3 1 3
Output
3
Input
6 7
1 2 1
3 2 5
2 4 2
2 5 2
2 6 9
5 4 3
4 3 4
Output
6
Note

In the first sample the maximum trail can be any of this trails: .

In the second sample the maximum trail is .

In the third sample the maximum trail is .

题意:给出一个有向带权值的图,要求出最长递增链路的长度。也就是当前边的权值要大于前一条边的。

思路:先对边按权值排序,然后dp,edge表示边的dp,node表示点的dp,然后进行更新

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=300010;
struct A
{
    int x,y,w;
    bool operator<(const A & a)const
    {
        return w<a.w;
    }
}e[maxn];
int edge[maxn],node[maxn];
int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
    sort(e+1,e+m+1);
    for(int i=1;i<=m;i++)
    {
        int j=i;
        while(j<=m&&e[j].w==e[i].w)
        {
            int x=e[j].x;
            edge[j]=max(edge[j],node[x]+1);
            j++;
        }
        j=i;
        while(j<=m&&e[j].w==e[i].w)
        {
            int y=e[j].y;
            node[y]=max(node[y],edge[j]);
            j++;
        }
        i=j-1;
    }
    int ans=0;
    for(int i=1;i<=m;i++)ans=max(ans,edge[i]);
    printf("%d\n",ans);
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值