20171029校内训练

 

       LGL帮n个人买东西,有m个物品给他选择。每件物品有一个价格c[i]和美丽度d[i]。每一个人都只需要买一个物品,但是他们都很挑剔并且奢侈,第i个人需要买的东西的价格大等于a[i],美丽度大等于b[i]。每个物品只能买给一个人,请问LGL最少要花多少钱?如果无法全部满足,输出-1。

输入格式:

第一行为两个整数n、m,接下来的n行每行两个整数a[i]、b[i],再接下来的m行每行两个整数c[i]、d[i]。

输出格式:

一个整数,表示LGL最少花钱数。

样例输入

样例输出

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

12

样例解释:

物品

1

2

2

3

3

6

4

7

数据范围:

对于100%的数据:1<=n、m<=100000,1<=其他数字<=109

 

 

加密

       LGL找了n个人来加密一个含有n个数字的密码。他的方法是:找n个人记住每一个数字c[i],然后每个人计算其他人的数字之和mod 98765431作为加密后的密码。但是ditoly只用了5秒钟就算出了他的密码,这让他十分气馁。于是他要用更高级的加密方式:即做上述过程x次。LGL想看看ditoly现在要多少秒才能算出来,所以他请你帮他算出加密后的n个数字。

输入格式:

第一行为两个整数n、x,接下来n行每行一个整数c[i]。

输出格式:

n行,每行一个整数,表示加密后的每一个数。

样例输入

样例输出

3 4
1
0
4

26
25
29

样例解释:

       算就是了。

数据范围:

对于100%的数据:1<=n<=50000,1<=x<=1414213562,1<=c[i]<=90000000。

 显然是构造矩阵啊

 显然,原先矩阵为主对角线上全部为1,其余全0的矩阵,然后每次乘一个主对角线上全部为0,其余全1的矩阵

第i行的答案为最终矩阵的第i行的第j列*c[j](1<=j<=n)

但显然,这样太慢

我们会发现,最终矩阵的主对角线上的数都相等,其余的数也都相等,即这个矩阵只有两种数。

不妨把主对角线上的数记为b,其余的数记为a。如果我们能找出一个矩阵使得能快速把a,b更新出下一组a,b,那么原问题就可解答。显然初始a=0,b=1。

我们发现,新的b等于a*(n-1),新的a等于a*(n-2)+b(自己模拟一下乘的过程就知道了)

于是,我们找到满足下列式子的矩阵

显然

 

记sum为c[i]之和,第i行答案为sum*a-c[i]*(a-b),注意,求sum时要随手一膜,不然就等着爆long long 吧

然后便可在O(2^3*log(x)+n)时间内解决该题。

花费

 LGL进入他的豪宅需要密码。他的密码长度为m,并且由n个不同字母构成。现在他想把密码改成回文的,他可以在任意位置添加或删除字母,而第i个字母都有不同的添加花费a[i]和删除花费b[i]。请问LGL最少要花多少钱才能把密码改成回文的?

输入格式:

第一行为两个整数n、m,接下来的n行每行一个字母和两个数a[i]和b[i],表示该字母的添加花费和删除花费。

输出格式:

一个整数,表示最小花费。

样例输入

样例输出

3 4
abcb
a 1000 1100
b 350 700
c 200 800

900

样例解释:

                     变成了bcbabcb。

数据范围:

对于100%的数据:1<=m<=2000、1<=n<=26,0<=a[i]、b[i]<=10000。

我们可以发现,把一个字母删去或者添加的效果是一样的,所以操作这个字母的花费为这两种操作的最小值

即删去黑色段最左边的一个红色字母的效果等同于在黑色段右边加入一个字母

我们用dp[i][j]表示在原数组内的i到j段的字母形成回文所需的花费,显然dp[i][i]=0

 dp[i][j]=min(dp[i+1][j]+cost[c[i]],dp[i][j-1]+cost[c[j]],dp[i+1][j-1](c[i]==c[j]))

即黑色段形成回文相当于把已成回文的橙色段再加一个绿色字符

若这两个绿色字符相等,那么黑色段回文代价也可以是橙色段回文代价

答案为dp[0][n-1]

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int cost[31],dp[2011][2011];
char c[2001];
int main()
{
    freopen("cost.in","r",stdin);freopen("cost.out","w",stdout);
    memset(cost,127/3,sizeof(cost));memset(dp,127/3,sizeof(dp));
    int n,m;scanf("%d%d",&n,&m);
    scanf("%s",c);
    for(int i=0;i<n;i++)
    {
        char s[2];int a,b;
        scanf("%s%d%d",s,&a,&b);cost[s[0]-'a']=min(a,b);
    }
    for(int i=0;i<m;i++)dp[i][i]=0,dp[i][i-1]=0;
    for(int len=2;len<=m;len++)
    for(int i=0;i+len-1<m;i++)
    {
        int j=i+len-1;
        if(c[i]==c[j])dp[i][j]=dp[i+1][j-1];
        dp[i][j]=min(dp[i+1][j]+cost[c[i]-'a'],min(dp[i][j],dp[i][j-1]+cost[c[j]-'a']));
    }
    cout<<dp[0][m-1];
    return 0;
}
View Code

 

posted @ 2017-10-31 20:21  lher  阅读(159)  评论(0编辑  收藏  举报