【20171029校内模拟赛】无题
T1 时限1s,其余0.5s,运行内存上限64MB.不开启任何优化,评测机运行效率约为4e8.
T1 买(buy)
Description
LGL帮n个人买东西,有m个物品给他选择。每件物品有一个价格c[i]和美丽度d[i]。每一个人都只需要买一个物品,但是他们都很挑剔并且奢侈,第i个人需要买的东西的价格大等于a[i],美丽度大等于b[i]。每个物品只能买给一个人,请问LGL最少要花多少钱?如果无法全部满足,输出-1。
Input
第一行为两个整数n、m,接下来的n行每行两个整数a[i]、b[i],再接下来的m行每行两个整数c[i]、d[i]。
Output
一个整数,表示LGL最少花钱数。
Sample Input
4 7
1 1
2 3
1 4
4 2
3 2
2 1
4 3
5 2
5 4
2 6
4 4
Sample Output
12
Hint
样例解释
人 物品 1 2 2 3 3 6 4 7 数据规模
对于100%的数据:\(1 \leq n,m \leq 100000\),\(1 \leq 其他数字 \leq 10^9\)。
Solution
考虑按美丽度从大到小排序,用< set > 维护美丽度比当前人大的的价格,查询的时候找lower_bound即可,时间复杂度\(O((n+m)\log (n+m))\)
Code
#include <stdio.h>
#include <algorithm>
#include <set>
#define R register
#define MN 100005
#define ll long long
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
inline int read(){
R int x; R bool f; R char c;
for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
return f?-x:x;
}
struct sth{
int c,v;
inline bool operator <(const sth &b)const{
return v>b.v;
}
}per[MN],th[MN];
int n,m;ll ans;
std::multiset<int> s;
std::multiset<int>::iterator it;
int main(){
file(buy);n=read(),m=read();
for (R int i=1; i<=n; ++i)
per[i].c=read(),per[i].v=read();
for (R int i=1; i<=m; ++i)
th[i].c=read(),th[i].v=read();
std::sort(per+1,per+n+1);std::sort(th+1,th+m+1);
for (R int i=1,j=1; i<=n; ++i){
while(j<=m&&per[i].v<=th[j].v) s.insert(th[j++].c);
it=s.lower_bound(per[i].c);
if (it==s.end()){
puts("-1");
return 0;
}ans+=*(it);s.erase(it);
}printf("%lld\n",ans);
}
T2 加密(password)
Description
LGL找了n个人来加密一个含有n个数字的密码。他的方法是:找n个人记住每一个数字c[i],然后每个人计算其他人的数字之和mod 98765431作为加密后的密码。但是ditoly只用了5秒钟就算出了他的密码,这让他十分气馁。于是他要用更高级的加密方式:即做上述过程x次。LGL想看看ditoly现在要多少秒才能算出来,所以他请你帮他算出加密后的n个数字。
Input
第一行为两个整数n、x,接下来n行每行一个整数c[i]。
Output
n行,每行一个整数,表示加密后的每一个数。
Sample Input
3 4
1
0
4
Sample Output
26
25
29
Hint
对于100%的数据:1<=n<=50000,1<=x<=1414213562,1<=c[i]<=90000000。
Solution
发现每次结果一定含有+/- vi 然后,去掉vi以后结果记为ai的话,容易写出递推式:\(ai=(n-1)ai-1+(-1)^{(i-1)} \Sigma vj\)
容易构造出矩阵,然后快速幂即可,时间复杂度\(O(n).\)
Code
#include <stdio.h>
#include <string.h>
#define R register
#define MN 50005
#define mod 98765431
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
#define end fclose(stdin);fclose(stdout)
inline int read(){
R int x; R bool f; R char c;
for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
return f?-x:x;
}
struct mat{
int a[2][2];
inline void clear(){memset(a,0,sizeof(a));}
mat operator*(const mat &b)const{
mat c;c.clear();
for (R int i=0; i<2; ++i)
for (R int j=0; j<2; ++j)
for (R int k=0; k<2; ++k)
c.a[i][j]=(c.a[i][j]+1ll*a[i][k]*b.a[k][j])%mod,c.a[i][j]+=mod,c.a[i][j]>=mod?c.a[i][j]-=mod:0;
return c;
}
}modify,fir,ans;
inline mat pw(mat a,int k){
mat p;p.clear();for (R int i=0; i<2; ++i) p.a[i][i]=1;
for (; k; a=a*a,k>>=1) if (k&1) p=p*a;
return p;
}
int n,x,v[MN],sum;
int main(){
file(password);n=read();x=read();modify.clear();
modify.a[0][0]=n-1,modify.a[1][0]=n-1,modify.a[1][1]=-1,modify.a[0][1]=0;modify=pw(modify,x-1);
for (R int i=1; i<=n; ++i) v[i]=read()%mod,sum+=v[i],sum>=mod?sum-=mod:0;
for (R int i=1; i<=n; ++i){
fir.clear();fir.a[0][0]=0,fir.a[0][1]=sum;ans=fir;
ans=fir*modify;ans.a[0][0]+=(x&1)?(sum-v[i]):(v[i]-sum);
ans.a[0][0]=(ans.a[0][0]%mod+mod)%mod;printf("%d\n",ans.a[0][0]);
}end;return 0;
}
T3 花费 (cost)
Description
LGL进入他的豪宅需要密码。他的密码长度为m,并且由n个不同字母构成。现在他想把密码改成回文的,他可以在任意位置添加或删除字母,而第i个字母都有不同的添加花费a[i]和删除花费b[i]。请问LGL最少要花多少钱才能把密码改成回文的?
Input
第一行为两个整数n、m,接下来的n行每行一个字母和两个数a[i]和b[i],表示该字母的添加花费和删除花费。
Output
一个整数,表示最小花费。
Sample Input
3 4
abcb
a 1000 1100
b 350 700
c 200 800
Sample Output
900
Hint
样例解释
变成了bcbabcb。
数据规模
对于100%的数据:1<=m<=2000、1<=n<=26,0<=a[i]、b[i]<=10000。
Solution
显然添加字母与删除字母是没有区别的,容易写出区间DP,dp方程为:$$f[l][r]={min(f[l+1][r]+v[l],f[l][r-1]+v[r]) (s[l] != s[r]); f[l+1}r-1$$
Code
#include <stdio.h>
#define MN 2005
#define R register
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
#define end fclose(stdin);fclose(stdout)
inline int read(){
R int x; R bool f; R char c;
for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
return f?-x:x;
}
int f[MN][MN],v[52],n,m;char s[MN];
inline int min(int a,int b){return a<b?a:b;}
inline int getv(char c){return c>'Z'?c-'a'+26:c-'A';}
int main(){
file(cost);n=read(),m=read();scanf("%s",s+1);
for (R int i=0; i<52; ++i) v[i]=10001;
for (R int i=1; i<=n; ++i){
R char c=getchar();while((c<'a'||c>'z')&&(c<'A'||c>'Z')) c=getchar();
v[getv(c)]=min(v[getv(c)],min(read(),read()));
}for (R int i=1; i<=m; ++i) f[i][i]=0;
for (R int l=2; l<=m; ++l)
for (R int i=1,j; i<=m-l+1; ++i){
if (s[i]==s[j=i+l-1])
f[i][j]=f[i+1][j-1];
else f[i][j]=min(f[i+1][j]+v[getv(s[i])],f[i][j-1]+v[getv(s[j])]);
}printf("%d",f[1][m]);end;return 0;
}