ICPC 2018焦作赛区网络赛部分题解

transport ship(运输船)

题目描述

There are N different kinds of transport ships on the port. The i^th kind of ship can carry the weight of V[i] and the number of the ith kind of ship is 2C[i]-1. How many different schemes there are if you want to use these ships to transport cargo with a total weight of S? It is required that each ship must be full-filled. Two schemes are considered to be the same if they use the same kinds of ships and the same number for each kind.

海港里有N中不同的运输船,第i种运输船可以搭载vi重量的货物,这种船的数量是2^(c[i]-1),如果你想用这些船只去搭载S吨的货物,那么有多少种不同的方案?每艘船都必须装满货物。如果用了相同种类的运输船且每种运输船的数量相同,那么视为相同的方案。

输入

The first line contains an integer T(1≤T≤20), which is the number of test cases. 
For each test case: 
The first line contains two integers: N(1≤N≤20), Q(1≤Q≤10000), representing the number of kinds of ships and the number of queries.
For the next N lines, each line contains two integers: V[i] (1≤V[i]≤20), C[i] (1≤C[i]≤20), representing the weight the i^th kind of ship can carry, and the number of the i^th kind of ship is 2C[i]-1.
For the next Q lines, each line contains a single integer: S (1≤S≤10000), representing the queried weight

 

输出

For each query, output one line containing a single integer which represents the number of schemes for arranging ships. Since the answer may be very large, output the answer modulo 1000000007

输出答案,对1e9+7取模.

复制样例数据

1
1 2
2 1
1
2

样例输出

0
1

此类问题可以看做一种背包问题——因为船必须满装货物,那就可以把一艘船等价成它承载的货物。因为“个数”的数据涉及2次幂,范围较大,所以这不能算简单的01背包模板,因为如果按照普通做法会极大超时。不过这种二次幂数据为背包问题的一个技巧提供了简便——二进制优化的多重背包。也就是把多个数据捆成一捆成为一个整体,这样在空间较大时就会直接把较大的数据纳入统计,避免了赘余计算,当空间较小时,可以由这些二进制倍的数据拼成你想要的数据组,因为这些二进制数据可以表示任何倍的本身数据。

假设本题的状态(DP数组下标)是当前运载了多少货物。

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include<queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll nextlong()
{
    ll tmp = 0, si = 1;
    char c;
    c = getchar();
    while (c > '9' || c < '0')
    {
        if (c == '-')
            si = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        tmp = tmp * 10 + c - '0';
        c = getchar();
    }
    return si * tmp;
}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
ll status[500000];
ll v[500000],c[500000];
int DETERMINATION()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0),cout.tie(0);
    ll t;
    t=nextlong();
    while(t--)
    {
        ll n,q;
        n=nextlong(),q=nextlong();
        reset(status,0);
        for(int i=1; i<=n; i++)
            v[i]=nextlong(),c[i]=nextlong();
        status[0]=1;//无论怎么样,装0吨货物有一种办法
        for(int i=1; i<=n; i++)
        {
            for(int j=0; j<c[i]; j++)
            {
                ll tmp=(v[i]<<j);//压缩
                for(int k=10500; k>=tmp; k--)
                {
                    status[k]+=status[k-tmp];//装载K吨货物时可以看做由k-tmp的状态加上tmp从而转移而来。
                    status[k]%=mod;
                }
            }
        }
        for(int i=1;i<=q;i++)
        {
            ll s;
            s=nextlong();
            println(status[s]);
        }
    }
    return 0;
}

Poor god water(可怜的圣水)

God Water likes to eat meat, fish and chocolate very much, but unfortunately, the doctor tells him that some sequence of eating will make them poisonous.
Every hour, God Water will eat one kind of food among meat, fish and chocolate. If there are 3 continuous hours when he eats only one kind of food, he will be unhappy. Besides, if there are 3 continuous hours when he eats all kinds of those, with chocolate at the middle hour, it will be dangerous. Moreover, if there are 3 continuous hours when he eats meat or fish at the middle hour, with chocolate at other two hours, it will also be dangerous.
Now, you are the doctor. Can you find out how many different kinds of diet that can make God Water happy and safe during N hours? Two kinds of diet are considered the same if they share the same kind of food at the same hour. The answer may be very large, so you only need to give out the answer module 1000000007.

圣水喜欢吃肉,鱼和巧克力。但不幸的是医生告诉他有一些饮食次序对他有害。

每个小时,圣水都会吃一种食物,介于肉,鱼和巧克力之间。如果存在三个连续的小时,他要是只吃了一种食物,那他就会不高兴。同样,如果三小时内他吃了所有的类别,并且巧克力介于三者之间,这就会对他很危险。而且,如果三小时之内在中间时刻吃了肉或者鱼,而两边缘时刻吃了巧克力,这也会很危险。

现在,你是医生,你能找出多少种方案使得圣水在N小时的进食时间内感到愉快并且拥有安全的饮食吗?

输入

The fist line puts an integer T that shows the number of test cases. (T≤1000)
Each of the next T lines contains an integer N that shows the number of hours. (1≤N≤10^10)

 

输出

For each test case, output a single line containing the answer.

这是一个矩阵快速幂问题。因为不能出现三个连续,每一次对方案进行修改(如果只加一个)都需要关注此位置前两个的字母组合是什么,根据数据范围这很难,所以可以一次性加两个。

比如FF组合后边要接上一个CM组合,这种情况就是可以的,而FF后边接上一个FC就是不行的。因此根据这些关系(已知的二元组合之间是否可以拼接)列出一个矩阵即可。

但是N可以是奇数,所以需要特别添加另一个矩阵:用于由本位置的前两个字母组合决定最后一个字母的可行方案。在进行完偶数次矩阵快速幂之后乘这个矩阵就可以得解。

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include<queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll nextlong()
{
    ll tmp = 0, si = 1;
    char c;
    c = getchar();
    while (c > '9' || c < '0')
    {
        if (c == '-')
            si = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        tmp = tmp * 10 + c - '0';
        c = getchar();
    }
    return si * tmp;
}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
struct matrix
{
    ll mat[9][9];
    ll r=9,c=9;
};
matrix multiply(matrix a,matrix b,ll md)
{
    matrix ans;
    reset(ans.mat,0);
    ans.r=a.r,ans.c=b.c;
    for(int i=0;i<a.c;i++)
    {
        for(int j=0;j<b.r;j++)
            for(int k=0;k<a.r;k++)
                ans.mat[i][j]=(ans.mat[i][j]+(a.mat[i][k]*b.mat[k][j])%md)%md;
    }
    return ans;
}
matrix power(matrix a,ll b,ll md)
{
    matrix ans;
    ans.c=a.c,ans.r=a.r;
    for(int i=0;i<ans.r;i++)
        for(int j=0;j<ans.c;j++)
    {
        if(i==j)
            ans.mat[i][j]=1;
        else
            ans.mat[i][j]=0;
    }
    while(b)
    {
        if((b&1))
            ans=multiply(a,ans,md);
        b>>=1;
        a=multiply(a,a,md);
    }
    return ans;
}
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    ll t;
    cin>>t;
    matrix init;
    int tmp[9][9]=
    {
        0,0,0,1,1,0,1,1,1,
        1,0,1,1,0,1,0,0,0,
        1,1,1,1,1,0,1,1,0,
        0,1,1,0,0,0,1,1,1,
        1,0,1,0,0,0,1,0,1,
        1,1,1,0,0,0,1,1,0,
        0,1,1,0,1,1,1,1,1,
        0,0,0,1,0,1,1,0,1,
        1,1,1,0,1,1,0,0,0,
    };
    for(int i=0;i<9;i++)
        for(int j=0;j<9;j++)
            init.mat[i][j]=tmp[i][j];
    matrix tmp2;
    reset(tmp2.mat,0);
    tmp2.mat[0][1]=tmp2.mat[0][2]=tmp2.mat[1][0]=tmp2.mat[1][1]
    =tmp2.mat[2][0]=tmp2.mat[2][1]=tmp2.mat[2][2]=1;
    tmp2.mat[3][0]=tmp2.mat[3][2]=tmp2.mat[4][0]=tmp2.mat[4][2]=
    tmp2.mat[5][0]=tmp2.mat[5][2]=tmp2.mat[6][0]=tmp2.mat[6][1]=
    tmp2.mat[6][2]=tmp2.mat[7][1]=tmp2.mat[7][2]=1;
    tmp2.mat[8][0]=tmp2.mat[8][1]=1;
    tmp2.r=9,tmp2.c=3;
//    for(int i=0;i<tmp2.r;i++)
//    {
//        for(int j=0;j<tmp2.c;j++)
//            cout<<tmp2.mat[i][j]<<" ";
//       cout<<endl;
//    }
    while(t--)
    {
        ll n;
        cin>>n;
        if(n==1)
        {
            cout<<3<<endl;
            continue;
        }
        else if(n==2)
        {
            cout<<9<<endl;
            continue;
        }
        else if(n==3)
        {
            cout<<20<<endl;
            continue;
        }
        else
        {
            ll tmp5=(n-2)/2;
            matrix finans=power(init,tmp5,mod);
            if(n&1)
                finans=multiply(finans,tmp2,mod);
            ll cnt=0;
            for(int i=0;i<finans.r;i++)
                for(int j=0;j<finans.c;j++)
                    cnt=(cnt+finans.mat[i][j])%mod;
            cout<<cnt<<endl;
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值