2015 Multi-University Training Contest 10 (hdu 5406-5416)数据结构+dp+矩阵快速幂+bitset优化拓扑排序+(dp&树状数组)

CRB and Candies

Problem Description

CRB has N different candies. He is going to eat K candies.
He wonders how many combinations he can select.
Can you answer his question for all K(0KN)?
CRB is too hungry to check all of your answers one by one, so he only asks least common multiple( LCM ) of all answers.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case there is one line containing a single integer N.
1T300
1N106

Output

For each test case, output a single integer – LCM modulo 1000000007(109+7) .

Sample Input

5
1
2
3
4
5

Sample Output

1
2
3
12
10
思路:
an=LCM(C0n,C1n,...,Cnn)
bn=LCM(1,2,3,...,n)
an=bn+1n+1
if(n==pk)bn=bn1p else bn=bn1

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1000010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int N;
LL p[maxn],b[maxn];
LL pow_mul(LL x,LL n){
    LL res=1;
    while(n){
        if(n&1)res=res*x%MOD;
        x=x*x%MOD;
        n>>=1;
    }
    return res;
}
LL inv(LL x){
    return pow_mul(x,MOD-2)%MOD;
}
bool judge(int x){
    int f=p[x];
    while(x%f==0&&x>1)x/=f;
    return x==1;
}
void init(){

    for(int i=1;i<maxn;i++)p[i]=i;
    for(int i=2;i<maxn;i++){
        if(p[i]==i){
            for(int j=i+i;j<maxn;j+=i){
                p[j]=i;
            }
        }
    }
    b[0]=1;
    for(int i=1;i<maxn;i++){
        if(judge(i))b[i]=p[i]*b[i-1]%MOD;
        else b[i]=b[i-1];
    }
}
int main(){
    init();
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&N);
        printf("%I64d\n",b[N+1]*inv(N+1)%MOD);
    }
    return 0;
}

CRB and His Birthday

Problem Description

Today is CRB’s birthday. His mom decided to buy many presents for her lovely son.
She went to the nearest shop with M Won(currency unit).
At the shop, there are N kinds of presents.
It costs Wi Won to buy one present of i-th kind. (So it costs k × Wi Won to buy k of them.)
But as the counter of the shop is her friend, the counter will give Ai×x+Bi candies if she buys x(x>0) presents of i-th kind.
She wants to receive maximum candies. Your task is to help her.
1T20
1M2000
1N1000
0Ai,Bi2000
1Wi2000

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains two integers M and N.
Then N lines follow, i-th line contains three space separated integers Wi, Ai and Bi.

Output

For each test case, output the maximum candies she can gain.

Sample Input

1
100 2
10 2 1
20 1 1

Sample Output

21

Hint

CRB’s mom buys 10 presents of first kind, and receives 2 × 10 + 1 = 21 candies.

思路: dp[i][j][0] 表示前i个花了j元钱,并且不包含第i个的最大价值, dp[i][j][1] 表示包含第i个的价值,第一次包含i要加A,B,以后只需要加A就行了

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=2010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int N,M;
int dp[maxn][2];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&M,&N);
        memset(dp,0,sizeof(dp));
        int w,a,b;
        for(int i=0;i<N;i++){
            scanf("%d%d%d",&w,&a,&b);
            for(int j=w;j<=M;j++){
                dp[j][1]=max(dp[j][1],max(dp[j-w][0]+a+b,dp[j-w][1]+a));
            }
            for(int j=w;j<=M;j++){
                dp[j][0]=dp[j][1];
            }
        }
        printf("%d\n",dp[M][1]);
    }
    return 0;
}

CRB and Puzzle

Problem Description

CRB is now playing Jigsaw Puzzle.
There are N kinds of pieces with infinite supply.
He can assemble one piece to the right side of the previously assembled one.
For each kind of pieces, only restricted kinds can be assembled with.
How many different patterns he can assemble with at most M pieces? (Two patterns P and Q are considered different if their lengths are different or there exists an integer j such that j-th piece of P is different from corresponding piece of Q.)

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains two integers N, M denoting the number of kinds of pieces and the maximum number of moves.
Then N lines follow. i-th line is described as following format.
ka1a2...ak
Here k is the number of kinds which can be assembled to the right of the i-th kind. Next k integers represent each of them.
1T20
1N50
1M105
0kN
1a1<a2<<akN

Output

For each test case, output a single integer - number of different patterns modulo 2015.

Sample Input

1
3 2
1 2
1 3
0

Sample Output

6
Hint
possible patterns are ∅, 1, 2, 3, 1→2, 2→3

思路:矩阵快速幂,dp[i][j]表示前i个最后一个是j的方案数,那么可以构造矩阵进行转移,然后求所有的方案和,只需要多加一行一列表示和就行了

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=55;
const int maxm=1010;
const int MOD=2015;
const int INF=0x3f3f3f3f;
int N,M;
struct Matrix{
    int mat[maxn][maxn];
    int n,m;
    Matrix(int _n=0,int _m=0){
        n=_n,m=_m;
        memset(mat,0,sizeof(mat));
    }
    Matrix operator*(const Matrix &a)const{
        Matrix res(n,m);
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                for(int k=0;k<n;k++){
                    res.mat[i][j]=(res.mat[i][j]+mat[i][k]*a.mat[k][j])%MOD;
                }
            }
        }
        return res;
    }
} ;

Matrix pow_mul(Matrix A,int n){
    Matrix res(A.n,A.m);
    for(int i=0;i<=res.n;i++)res.mat[i][i]=1;
    while(n){
        if(n&1)res=res*A;
        A=A*A;
        n>>=1;
    }
    return res;
}
void print(Matrix A){
    for(int i=0;i<=N;i++){
        for(int j=0;j<=N;j++){
            cout<<A.mat[i][j]<<" ";
        }
        cout<<endl;
    }
}
int main(){
    int T,k,x;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&N,&M);
        Matrix A(N+1,N+1),B(N+1,N+1);
        for(int i=1;i<=N;i++){
            scanf("%d",&k);
            for(int j=0;j<k;j++){
                scanf("%d",&x);
                A.mat[x-1][i-1]=1;
            }
        }
        for(int i=0;i<=N;i++)A.mat[N][i]=1,B.mat[i][0]=1;
        B.mat[N][0]=0;
        A=pow_mul(A,M-1);
        A=A*B;
        int ans=0;
        for(int i=0;i<=N;i++){
            ans=(ans+A.mat[i][0])%MOD;
        }
        printf("%d\n",ans+1);
    }
    return 0;
}

CRB and Queries

Problem Description

There are N boys in CodeLand.
Boy i has his coding skill Ai.
CRB wants to know who has the suitable coding skill.
So you should treat the following two types of queries.
Query 1: 1 l v
The coding skill of Boy l has changed to v.
Query 2: 2 l r k
This is a report query which asks the k-th smallest value of coding skill between Boy l and Boy r(both inclusive).

Input

There are multiple test cases.
The first line contains a single integer N.
Next line contains N space separated integers A1, A2, …, AN, where Ai denotes initial coding skill of Boy i.
Next line contains a single integer Q representing the number of queries.
Next Q lines contain queries which can be any of the two types.
1N,Q105
1Ai,v109
1lrN
1krl+1

Output

For each query of type 2, output a single integer corresponding to the answer in a single line.

Sample Input

5
1 2 3 4 5
3
2 2 4 2
1 3 6
2 2 4 2

Sample Output

3
4
裸地动态区间第k大,以前线段树套treap的代码交上去一直超时,最后改成BIT套treap就过了。。。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
#define lson lc,L,M
#define rson rc,M+1,R
const int maxn=100010;
const int INF=1000000000;
int N,M;
int a[maxn];
int tot;

struct Node
{
    int ch[2];
    int r;//优先级
    int v;//值
    int s;
    int cnt;//自身重复次数
    void init(int val){v=val;ch[0]=ch[1]=0;s=cnt=1;r=rand();}
    int cmp(int x)const
    {
        if(x==v)return -1;
        return x<v?0:1;
    }

}tree[maxn*30];
void maintain(int x)
{
    tree[x].s=tree[x].cnt;
    tree[x].s+=tree[tree[x].ch[0]].s+tree[tree[x].ch[1]].s;
}
void rotate(int &o,int d)
{
    int k=tree[o].ch[d^1];
    tree[o].ch[d^1]=tree[k].ch[d];
    tree[k].ch[d]=o;
    maintain(o);
    maintain(k);
    o=k;
}
void insert(int &o,int x)
{
    if(!o)
    {
        o=++tot;
        tree[o].init(x);
    }
    else
    {
        if(x==tree[o].v)tree[o].cnt++;
        else
        {
            int d=(x<tree[o].v?0:1);
            insert(tree[o].ch[d],x);
            if(tree[tree[o].ch[d]].r>tree[o].r)
                rotate(o,d^1);
        }
    }
    maintain(o);
}
void remove(int &o,int x)
{
    if(!o)return;
    int d=tree[o].cmp(x);
    if(d==-1)
    {
        int u=o;
        if(tree[o].cnt>1)tree[o].cnt--;
        else if(tree[o].ch[0]&&tree[o].ch[1])
        {
            int d2=(tree[tree[o].ch[0]].r>tree[tree[o].ch[1]].r?1:0);
            rotate(o,d2);
            remove(tree[o].ch[d2],x);
        }
        else
        {
            if(!tree[o].ch[0])o=tree[o].ch[1];
            else o=tree[o].ch[0];
            tree[u]=tree[0];
        }
    }
    else remove(tree[o].ch[d],x);
    if(o)maintain(o);
}
//返回最大值
int get_max(int o)
{
    while(tree[o].ch[0])o=tree[o].ch[0];
    return tree[o].v;
}
//返回最小值
int get_min(int o)
{
    while(tree[o].ch[1])o=tree[o].ch[1];
    return tree[o].v;
}
//返回val的前驱,如果没有的话返回y
//y的初值可赋成0,表示没有前驱
int get_pred(int o,int val,int y)
{
    if(!o)return y;
    if(tree[o].v<=val)//注意大于等于号
        return get_pred(tree[o].ch[1],val,tree[o].v);
    else return get_pred(tree[o].ch[0],val,y);
}
//返回val的后继,如果没有的话返回y
//y的初值可赋成0,表示没有后继
int get_succ(int o,int val,int y)
{
    if(!o)return y;
    if(tree[o].v>=val)return get_succ(tree[o].ch[0],val,tree[o].v);
    else return get_succ(tree[o].ch[1],val,y);
}
//返回第k大的元素的值
int get_kth(int o,int k)
{
    if(!o)return 0;
    if(k<=tree[tree[o].ch[0]].s)return get_kth(tree[o].ch[0],k);
    else if(k>tree[tree[o].ch[0]].s+tree[o].cnt)
        return get_kth(tree[o].ch[1],k-tree[tree[o].ch[0]].s-tree[o].cnt);
    return tree[o].v;
}
//返回val的排名
int get_rank(int o,int val)
{
    if(!o)return 0;
    int lsize=tree[tree[o].ch[0]].s;
    if(val<tree[o].v)
        return get_rank(tree[o].ch[0],val);
    else if(val>tree[o].v)
        return get_rank(tree[o].ch[1],val)+lsize+tree[o].cnt;
    return lsize+tree[o].cnt;
}

int root[maxn<<2];
int lowbit(int x){
    return x&(-x);
}
void add(int x,int val){
    while(x<=N){
        insert(root[x],val);
        x+=lowbit(x);
    }
}
void update(int x,int y1,int y2){
    while(x<=N){
        remove(root[x],y1);
        insert(root[x],y2);
        x+=lowbit(x);
    }
}
int query(int x,int val){
    int sum=0;
    while(x){
        sum+=get_rank(root[x],val);
        x-=lowbit(x);
    }
    return sum;
}

int fastget()
{
    char c; int ans=0; c=getchar();
    while (! (c>='0' && c<='9')) c=getchar();
    while (c>='0' && c<='9')
    {
        ans=(ans<<3)+(ans<<1)+c-'0';
        c=getchar();
    }
    return ans;
}
int main()
{
    int op;
    int x,y;
    while(scanf("%d",&N)!=EOF)
    {
        tot=0;
        for(int i=1;i<=N;i++)a[i]=fastget(),root[i]=0;
        M=fastget();
        for(int i=1;i<=N;i++)add(i,a[i]);

        while(M--)
        {
            op=fastget();
            x=fastget();
            y=fastget();
            if(op==1){
                update(x,a[x],y);
                a[x]=y;
            }
            else
            {
                int k;
                k=fastget();
                int l=0,r=INF,ans=0;
                while(l<r)
                {
                    int mid=(l+r)>>1;
                    if(query(y,mid)-query(x-1,mid)>=k)ans=mid,r=mid;
                    else l=mid+1;
                }
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}

好像还可以整体二分,并不知道这是什么, 等会补一下

CRB and String

Problem Description

CRB has two strings s and t.
In each step, CRB can select arbitrary character c of s and insert any character d (d ≠ c) just after it.
CRB wants to convert s to t. But is it possible?

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case there are two strings s and t, one per line.
1T105
1|s||t|105
All strings consist only of lowercase English letters.
The size of each input file will be less than 5MB.

Output

For each test case, output “Yes” if CRB can convert s to t, otherwise output “No”.

Sample Input

4
a
b
cat
cats
do
do
apple
aapple

Sample Output

No
Yes
Yes
No

思路:由于是在s串上进行操作,s必须包含在t串中,还有t串的第1个元素必须相等且连续出现的次数也必须小于等于s串的,其他的连续出现的就不需要考虑了,因为可以在连续出现之前一直添加,如样例4,可以在a后添加多少个 p都没问题。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
char s1[maxn],s2[maxn];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%s%s",s1,s2);
        bool flag=true;
        int cur=0;
        int len1=strlen(s1),len2=strlen(s2);
        for(int i=0;s2[i];i++){
            if(s1[cur]==s2[i])cur++;
            if(cur==len1)break;
        }
        if(cur<len1||s1[0]!=s2[0]){
            printf("No\n");
            continue;
        }
        int pos1=0,pos2=0;
        while(pos1+1<len1&&s1[pos1+1]==s1[pos1])pos1++;
        while(pos2+1<len2&&s2[pos2+1]==s2[pos2])pos2++;
        if(pos1<pos2){
            printf("No\n");
        } else {
            printf("Yes\n");
        }
    }
    return 0;
}

CRB and Tree

Problem Description

CRB has a tree, whose vertices are labeled by 1, 2, …, N. They are connected by N – 1 edges. Each edge has a weight.
For any two vertices u and v(possibly equal), f(u,v) is xor(exclusive-or) sum of weights of all edges on the path from u to v.
CRB’s task is for given s, to calculate the number of unordered pairs (u,v) such that f(u,v) = s. Can you help him?

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains an integer N denoting the number of vertices.
Each of the next N - 1 lines contains three space separated integers a, b and c denoting an edge between a and b, whose weight is c.
The next line contains an integer Q denoting the number of queries.
Each of the next Q lines contains a single integer s.
1T25
1N105
1Q10
1a,bN
0c,s105
It is guaranteed that given edges form a tree.

Output

For each query, output one line containing the answer.

Sample Input

1
3
1 2 1
2 3 2
3
2
3
4

Sample Output

1
1
0

Hint

For the first query, (2, 3) is the only pair that f(u, v) = 2.
For the second query, (1, 3) is the only one.
For the third query, there are no pair (u, v) such that f(u, v) = 4.

思路:首先求出每个点到根节点的路径的异或值,那么两点之间路径的异或值就是两点的异或,然后查询是查询。我比赛的时候是吧他们插入到字典树中,然后dfs,其实也不用,这样太麻烦,直接暴力每个点,然后统计值等于 s ^ valu 的有多少个就行了

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int head[maxn];
int tot,N,Q;
struct node{
    int v,next,w;
}edge[maxn*2];
int XOR[maxn];
void add_edge(int u,int v,int w){
    edge[tot].v=v;
    edge[tot].next=head[u];
    edge[tot].w=w;
    head[u]=tot++;
}
void dfs(int u,int fa,int x){
    XOR[u]=x;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v==fa)continue;
        dfs(v,u,x^(edge[i].w));
    }
}
struct Trie{
    int ch[maxn*32][2];
    int val[maxn*32];
    int sz;
    void clear(){
        memset(ch[0],0,sizeof(ch[0]));
        memset(val,0,sizeof(val));
        sz=1;
    }
    void insert(int x){
        int u=0;
        for(int i=31;i>=0;i--){
            int c=(x&(1<<i))?1:0;
            if(!ch[u][c]){
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz]=0;
                ch[u][c]=sz++;
            }
            u=ch[u][c];
            val[u]++;
        }
    }
    LL solve(int u1,int u2,int x,int depth){
        if(depth<0)return 0;
        if(depth==0){
            if(x&(1<<depth)){
                if(u1!=u2) return 1LL*val[ch[u1][0]]*val[ch[u2][1]]+1LL*val[ch[u1][1]]*val[ch[u2][0]];
                else return 1LL*val[ch[u1][0]]*val[ch[u2][1]];
            } else {
                if(u1!=u2)return 1LL*val[ch[u1][0]]*val[ch[u2][0]]+1LL*val[ch[u1][1]]*val[ch[u2][1]];
                else {
                    LL tmp=0;
                    int a=val[ch[u1][0]],b=val[ch[u1][1]];
                    if(a>1)tmp+=1LL*(a-1)*a/2;
                    if(b>1)tmp+=1LL*(b-1)*b/2;
                    return tmp;
                }
            }
        }
        LL ans=0;
        if(x&(1<<depth)){
            if(ch[u1][0]&&ch[u2][1]){
                ans+=solve(ch[u1][0],ch[u2][1],x,depth-1);
            }
            if(u1!=u2&&ch[u1][1]&&ch[u2][0])
                ans+=solve(ch[u1][1],ch[u2][0],x,depth-1);
        } else {
            if(ch[u1][0]&&ch[u2][0]){
                ans+=solve(ch[u1][0],ch[u2][0],x,depth-1);
            }

            if(ch[u1][1]&&ch[u2][1])
                ans+=solve(ch[u1][1],ch[u2][1],x,depth-1);
        }
        return ans;
    }
}tree;
int main(){
    int T,u,v,w;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&N);
        tot=0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<N;i++){
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w);
            add_edge(v,u,w);
        }
        dfs(1,-1,0);
        tree.clear();
        for(int i=1;i<=N;i++){
            tree.insert(XOR[i]);
        }
        scanf("%d",&Q);
        while(Q--){
            scanf("%d",&w);
            LL ans=tree.solve(0,0,w,31);
            if(w==0)ans+=N;
            printf("%I64d\n",ans);
        }
    }
    return 0;
}
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int head[maxn];
int tot,N,Q;
struct node{
    int v,next,w;
}edge[maxn*2];
int XOR[maxn*2];
LL ans;
void add_edge(int u,int v,int w){
    edge[tot].v=v;
    edge[tot].next=head[u];
    edge[tot].w=w;
    head[u]=tot++;
}
void dfs(int u,int fa,int x){
    XOR[x]++;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v==fa)continue;
        dfs(v,u,x^(edge[i].w));
    }
}
void find(int u,int fa,int x,int sum){
    ans+=XOR[x^sum];
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v==fa)continue;
        find(v,u,x,sum^(edge[i].w));
    }
}
int main(){
    int T,u,v,w;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&N);
        tot=0;
        memset(head,-1,sizeof(head));
        memset(XOR,0,sizeof(XOR));
        for(int i=1;i<N;i++){
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w);
            add_edge(v,u,w);
        }
        dfs(1,-1,0);
        scanf("%d",&Q);
        while(Q--){
            scanf("%d",&w);
            ans=0;
            find(1,-1,w,0);
            if(w==0)ans+=N;
            printf("%I64d\n",ans/2);
        }
    }
    return 0;
}

CRB and Roads

Problem Description

There are N cities in Codeland.
The President of Codeland has a plan to construct one-way roads between them.
His plan is to construct M roads.
But CRB recognized that in this plan there are many redundant roads.
So he decided to report better plan without any redundant roads to President.
Help him!
The road (u, v) is redundant if and only if there exists a route from u to v without using it.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains two integers N and M denoting the number of cities and the number of roads in the President’s plan.
Then M lines follow, each containing two integers u and v representing a one-way road from u to v.
1T20
1N2104
1M105
1u,vN
The given graph is acyclic, and there are neither multiple edges nor self loops.

Output

For each test case, output total number of redundant roads.

Sample Input

1
5 7
1 2
1 3
1 4
1 5
2 4
2 5
3 4

Sample Output

2

思路: HDU 5413 CRB and Roads【bitset】

对于每个点u维护能到达它的点,然后进行拓扑排序,按照拓扑排序的顺序枚举每个点u,对于u能到达的点(通过反向边维护)按照拓扑序从大到小排序(拓扑序大的说明可以有很多点到它,也就是u可以通过这个点到达很多点),然后将v(能到达u的点,也就是反向边u能到的点)在反向边中能到的点来更新u,用bitset优化一下。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<bitset>
#include<numeric>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=10010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int N,M;
vector<int> edge[maxn],revEdge[maxn];
bitset<maxn> reach[maxn];
int w[maxn],fw[maxn],in[maxn];
int time_clock;
int main(){
    int T,u,v;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&N,&M);
        for(int i=0;i<=N;i++){
            edge[i].clear();
            revEdge[i].clear();
            reach[i].reset();
            reach[i][i]=1;
            in[i]=0;
        }
        for(int i=0;i<M;i++){
            scanf("%d%d",&u,&v);
            edge[u].push_back(v);
            revEdge[v].push_back(u);
            in[v]++;
        }
        time_clock=0;
        queue<int> q;
        for(int i=1;i<=N;i++){
            if(in[i]==0)q.push(i);
        }
        while(!q.empty()){
            u=q.front();
            q.pop();
            w[u]=++time_clock;
            fw[time_clock]=u;
            for(auto x : edge[u]){
                if(--in[x]==0){
                    q.push(x);
                }
            }
        }
        int ans=0;
        for(int i=1;i<=time_clock;i++){
            u=fw[i];
            sort(revEdge[u].begin(),revEdge[u].end(),[](int x,int y)->bool{return w[x]>w[y];});
            for(auto x : revEdge[u]){
                if(reach[u][x])ans++;
                reach[u]|=reach[x];
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

CRB and Apple

Problem Description

In Codeland there are many apple trees.
One day CRB and his girlfriend decided to eat all apples of one tree.
Each apple on the tree has height and deliciousness.
They decided to gather all apples from top to bottom, so an apple can be gathered only when it has equal or less height than one just gathered before.
When an apple is gathered, they do one of the following actions.
1. CRB eats the apple.
2. His girlfriend eats the apple.
3. Throw the apple away.
CRB(or his girlfriend) can eat the apple only when it has equal or greater deliciousness than one he(she) just ate before.
CRB wants to know the maximum total number of apples they can eat.
Can you help him?

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains a single integer N denoting the number of apples in a tree.
Then N lines follow, i-th of them contains two integers Hi and Di indicating the height and deliciousness of i-th apple.
1 ≤ T ≤ 48
1 ≤ N ≤ 1000
1 ≤ Hi, Di ≤ 109

Output

For each test case, output the maximum total number of apples they can eat.

Sample Input

1
5
1 1
2 3
3 2
4 3
5 1

Sample Output

4
思路:dp[i][j]表示两个人当前吃的苹果的可口度为i,j的吃的最大的苹果数,那么可以得到状态转移方程:
dp[i][j]=max(dp[i][k],1k<j)+1 i,j正好是对称的

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<bitset>
#include<numeric>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int N,cnt;
struct Node{
    int h,d;
    bool operator<(const Node &a)const{
        if(h!=a.h)return h>a.h;
        return d<a.d;
    }
}a[maxn];
int X[maxn];
int tree[maxn][maxn];
int maxv[maxn];
int lowbit(int x){
    return x&(-x);
}
void update(int x,int y,int val){
    while(y<=cnt+2){
        tree[x][y]=max(tree[x][y],val);
        y+=lowbit(y);
    }
}
int query(int x,int y){
    int ans=0;
    while(y){
        ans=max(ans,tree[x][y]);
        y-=lowbit(y);
    }
    return ans;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&N);
        cnt=0;
        memset(tree,0,sizeof(tree));
        for(int i=1;i<=N;i++){
            scanf("%d%d",&a[i].h,&a[i].d);
            X[cnt++]=a[i].d;
        }
        sort(a+1,a+1+N);
        sort(X,X+cnt);
        cnt=unique(X,X+cnt)-X;
        for(int i=1;i<=N;i++){
            a[i].d=lower_bound(X,X+cnt,a[i].d)-X+1;
        }
        for(int i=1;i<=N;i++){
            for(int j=1;j<=cnt+1;j++){
                maxv[j]=query(j,a[i].d);
            }
            for(int j=1;j<=cnt+1;j++){
                update(j,a[i].d,maxv[j]+1);
                update(a[i].d,j,maxv[j]+1);
            }
        }
        int ans=0;
        for(int i=1;i<=cnt+1;i++){
            ans=max(ans,query(i,cnt+1));
        }
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值