买
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 | 12 |
样例解释:
人 | 物品 |
1 | 2 |
2 | 3 |
3 | 6 |
4 | 7 |
数据范围:
对于100%的数据:1<=n、m<=100000,1<=其他数字<=109。
set大法好
考虑贪心,将物品和要求都按美丽度从大到小排序,接着按照人的顺序做:
加入一个新的人时,把所有美丽度能满足他的要求的物品加入一个按价格排序的set里,然后寻找set中价格能满足他的要求的物品中价格最低的物品。
如果没有就输出-1,有的话ans加上它,然后将它从set中删去。
#include<iostream> #include<cstdio> #include<algorithm> #include<set> using namespace std; inline int read(){ int t=1,num=0;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();} while(c>='0'&&c<='9'){num=num*10+c-'0';c=getchar();} return num*t; } const int N=100010; struct goods{int c,v;}a[N],b[N]; multiset<int> s; multiset<int>::iterator it; int n,m;long long ans; bool cmp(goods a,goods b){return a.v>b.v;} int main() { n=read();m=read(); for(int i=1;i<=n;i++)a[i].c=read(),a[i].v=read(); for(int i=1;i<=m;i++)b[i].c=read(),b[i].v=read(); sort(a+1,a+1+n,cmp);sort(b+1,b+1+m,cmp); int i,j=1; for(i=1;i<=n;i++){ while(j<=m&&a[i].v<=b[j].v)s.insert(b[j++].c); it=s.lower_bound(a[i].c); if(it==s.end()){ puts("-1");return 0; } ans+=*it;s.erase(it); } printf("%lld",ans); return 0; }
加密
LGL找了n个人来加密一个含有n个数字的密码。他的方法是:找n个人记住每一个数字c[i],然后每个人计算其他人的数字之和mod 98765431作为加密后的密码。但是ditoly只用了5秒钟就算出了他的密码,这让他十分气馁。于是他要用更高级的加密方式:即做上述过程x次。LGL想看看ditoly现在要多少秒才能算出来,所以他请你帮他算出加密后的n个数字。
输入格式:
第一行为两个整数n、x,接下来n行每行一个整数c[i]。
输出格式:
n行,每行一个整数,表示加密后的每一个数。
样例输入 | 样例输出 |
3 4 | 26 |
样例解释:
算就是了。
数据范围:
对于100%的数据:1<=n<=50000,1<=x<=1414213562,1<=c[i]<=90000000。
题解: 设sum=sum{a[i]},只要想到下一个a[i]=sum-a[i],下一个sum=(n-1)*sum就是矩阵乘法裸题。
我的作法与题解稍有不同但也是矩阵乘法。矩阵见代码
#include<cstdio> #include<cstring> #include<iostream> #define For(i,a,b) for(int i=a;i<=b;i++) #define ll long long using namespace std; const int mod=98765431; struct Yzyet{ll p[2][2];}ans,tmp; ll x,sum=0;int q[50010],n; inline Yzyet operator *(const Yzyet a,const Yzyet b){ Yzyet c;memset(c.p,0,sizeof(c.p)); For(i,0,1)For(k,0,1) if(a.p[i][k])For(j,0,1) c.p[i][j]=((c.p[i][j]+a.p[i][k]*b.p[k][j])%mod+mod)%mod; return c; } void init(){ ans.p[0][0]=0;ans.p[0][1]=1;ans.p[1][0]=ans.p[1][1]=0; tmp.p[0][0]=n-1;tmp.p[0][1]=0;tmp.p[1][0]=1;tmp.p[1][1]=-1; } void ksm(ll t){ while(t){ if(t&1)ans=ans*tmp; tmp=tmp*tmp; t>>=1; } } int main() { freopen("password.in","r",stdin); freopen("password.out","w",stdout); scanf("%d%lld",&n,&x);init();ksm(x); for(int i=1;i<=n;i++){ scanf("%d",&q[i]);sum=(sum+q[i])%mod; } for(int i=1;i<=n;i++){ int t=(x&1?-1:1)*q[i]; printf("%d\n",(((sum*ans.p[0][0])%mod+t)%mod+mod)%mod); } return 0; }
花费
LGL进入他的豪宅需要密码。他的密码长度为m,并且由n个不同字母构成。现在他想把密码改成回文的,他可以在任意位置添加或删除字母,而第i个字母都有不同的添加花费a[i]和删除花费b[i]。请问LGL最少要花多少钱才能把密码改成回文的?
输入格式:
第一行为两个整数n、m,接下来的n行每行一个字母和两个数a[i]和b[i],表示该字母的添加花费和删除花费。
输出格式:
一个整数,表示最小花费。
样例输入 | 样例输出 |
3 4 | 900 |
样例解释:
变成了bcbabcb。
数据范围:
对于100%的数据:1<=m<=2000、1<=n<=26,0<=a[i]、b[i]<=10000。
首先加一个字母和删一个字母其实是一样的,所以处理一个字母的花费就是min{a[i],b[i]}。接着直接区间dp即可。
#include<cstdio> int f[2010][2010]; int n,m,w[26]; char s[2010],c[5]; int min(int a,int b){return a<b?a:b;} int main() { freopen("cost.in","r",stdin); freopen("cost.out","w",stdout); scanf("%d%d",&m,&n); scanf("%s",s+1); for(int i=1;i<=m;i++){ int a,b;scanf("%s%d%d",c,&a,&b); w[c[0]-'a']=min(a,b); } for(int l=2;l<=n;l++){ for(int i=1;i+l-1<=n;i++){ int j=i+l-1; f[i][j]=min(f[i][j-1]+w[s[j]-'a'],f[i+1][j]+w[s[i]-'a']); if(s[i]==s[j])f[i][j]=min(f[i][j],f[i+1][j-1]); } } printf("%d\n",f[1][n]); return 0; }
本文由Yzyet编写,网址为www.cnblogs.com/Yzyet。非Yzyet同意,禁止转载,侵权者必究。