#### T1 榴莲罐头
题目
小郭同学的生日快到了, 她打算用N 天来庆祝。编程班的同学们的最近注意力不太集
中, 因此小郭想提供大家最喜欢的榴莲罐头来使大家高兴。她已经计算出了第i 天需要的罐
头数为Xi。
小郭的学校提供了许多服务给编程班的同学们, 包括一个出售食品的小卖部。小卖部出
售的榴莲罐头价格是起伏不定的,第i 天,榴莲罐头的价格是Wi 块钱一罐。小郭同学每天
可以购买任意数量的罐头,这些罐头可以立即发给同学们享用,也可以寄存在小卖部里,小
郭同学随时可以把它们取出来。寄存一个罐头的花费是k 块钱一天。
小郭同学想知道,她最少需要花费多少钱就能满足每天罐头的需求。
【输入】
第一行输入两个整数N 和K, N 表示庆祝活动持续N 天,K 为一个罐头寄存一天的花费。
接下来有N 行,每行输入两个整数Wi 和Xi。Wi 表示第i 天购买一个罐头的费用,Xi
表示第i 天需要的罐头数量。
【输出】
输出一个整数,表示小郭同学所需花费的最少费用。结果可能很大,mod 100000007
后再输出。
【样例输入1】
3 3
1 2
3 2
8 2
【样例输出1】
20
【样例输入2】
4 5
87 18
88 20
96 30
89 32
【样例输出2】
8964
【样例1解释】
共有3 天,寄存的费用为每天3 元
第1 天一共购买2 个罐头共花费1*2=2 元;
第2 天购买4 个罐头共花费3*4=12 元;
第3 天不购买罐头,改用第2 天多购买的2 个罐头,共花费2*3=6 元的寄存费用。
总花费2+12+6=20 元。
【数据范围】
对于30%的数据,1<=N<=100, 0<=K<=100。
对于70%的数据,1<=N<=5000, 0<=K<=1000。
对于100%的数据,1<=N<=1000000, 0<=K<=10000, 0<=Wi,Xi<=50000。
思路
代码实现
#include<cstdio>
#include<iostream>
#define p 100000007
using namespace std;
inline void _in(long long &d)
{
char t=getchar();
while(!isdigit(t))t=getchar()//isdigit用来判断是否为数字
for(d=0;isdigit(t);t=getchar())d=d*10+t-48;
}
int n;
long long Min=0x3FFFFFFE,k,a,b,ans;
int main()
{
//freopen("bignews12.in","r",stdin);
//freopen("can.out","w",stdout);
cin>>n>>k;
while(n--)
{
_in(a);_in(b);
Min=(Min+k>a)?a:Min+k;
ans=(ans+Min*b)%p;
}
cout<<ans;
}
收获
贪心应用以及isdigit
#### T2 哥斯拉大战金刚
题目
众所周知,哥斯拉和金刚是时代仇敌,大战一触即发。金刚为了打败哥斯拉,要先前往地心空洞获得战斧。金刚现在所在之处可以被视为一个n*m的网格图,S表示金刚目前的位置,T表示地心空洞的入口,X表示障碍物,.表示平地。在前往地心空洞之前,金刚必须先获得一系列打开地心空洞的钥匙(在地图上通过数字1,2,…,k表示),并且获得i类钥匙的前提是金刚已经获得了1,2,…,i-1类钥匙,金刚在拿到地图上所有种类的钥匙之后即可前往地心空洞的入口。另外,同一种类的钥匙可能有多把,金刚只需获得其中任意一把即可。金刚每一步可以朝上下左右四个方向中的一个移动一格,值得注意的是,哥斯拉为了阻挠金刚的计划,还在地图上设置了q个陷阱(在网格图中用G表示),金刚第一次进入某个陷阱需要花费额外的一步来破坏陷阱(这之后该陷阱即可被视为平地)。为了更好的掌握全局,请你帮金刚计算到达地心空洞入口所需要花费的最少步数。输入数据保证有解。
【输入】
第一行输入两个整数n,m,表示网格图的大小。
接下来n行,每行输入m个字符,表示地图。
【输出】
输出一行包含一个整数,表示金刚到达地心空洞入口所需要花费的最少步数。
【样例输入1】
```
5 5
XX13X
X.GXX
S...T
XXGXX
....2
```
【样例输出1】
```
24
```
【数据范围】
对于20%的数据,1<=n,m<=10
对于另30%的数据,没有陷阱
对于100%的数据,1<=n,m<=100,1<=k<=9,1<=q<=7
思路
代码实现
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
template <typename T>
inline void _read(T& x){
char ch=getchar();bool sign=true;
while(!isdigit(ch)){if(ch=='-')sign=false;ch=getchar();}
for(x=0;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+ch-'0';
if(!sign)x=-x;
}
int n,m;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int dis[105][105][11][135]; //dis[i][j][k][l]
char a[105][105];
int b[105][105];
int kx,ky,Tx,Ty;
struct node{
int x,y,keys,godz;
node(){}
node(int X,int Y,int K,int S){x=X;y=Y;keys=K;godz=S;}
};
int main(){
freopen("Godzilla.in","r",stdin);
freopen("Godzilla.out","w",stdout);
int i,j,k;
int cnt=0,all,max_key=0;
memset(dis,0x3c,sizeof(dis));
cin>>n>>m;
for(i=1;i<=n;i++){
scanf("%s",a[i]+1);
for(j=1;j<=m;j++){
if(a[i][j]=='S'){
kx=i;ky=j;
}
if(a[i][j]=='T'){
Tx=i;Ty=j;
}
if(a[i][j]=='G'){
b[i][j]=++cnt;
}
if(isdigit(a[i][j]))max_key=max(max_key,a[i][j]-'0');
}
}
all=(1<<cnt)-1;
queue<node> q;
dis[kx][ky][0][0]=0;
q.push(node(kx,ky,0,0));
int ans=1e9;
while(q.size()){
node t=q.front();q.pop();
int step=dis[t.x][t.y][t.keys][t.godz];
if(t.keys==max_key&&a[t.x][t.y]=='T'){
ans=min(ans,step);
}
for(i=0;i<4;i++){
int tx=t.x+dx[i],ty=t.y+dy[i],tk,ts;
if(tx<1||ty<1||tx>n||ty>n||a[tx][ty]=='X')continue;
if(isdigit(a[tx][ty])){
tk=t.keys;if(a[tx][ty]-'0'==t.keys+1)tk++;
ts=t.godz;
if(dis[tx][ty][tk][ts]>step+1){
dis[tx][ty][tk][ts]=step+1;
q.push(node(tx,ty,tk,ts));
}
}
else if(a[tx][ty]=='G'){
tk=t.keys;
ts=(t.godz|(1<<(b[tx][ty]-1)));
int ss;
if((t.godz&(1<<(b[tx][ty]-1)))==0)ss=step+2;
else ss=step+1;
if(dis[tx][ty][tk][ts]>ss){
dis[tx][ty][tk][ts]=ss;
q.push(node(tx,ty,tk,ts));
}
}
else {
tk=t.keys;
ts=t.godz;
if(dis[tx][ty][tk][ts]>step+1){
dis[tx][ty][tk][ts]=step+1;
q.push(node(tx,ty,tk,ts));
}
}
}
}
cout<<ans;
}
收获
状态压缩,数组新用法,复习了结构体。
#### T3 长城
为了抵御外敌,在长城沿线从西向东有连绵不断的 n 个烽火台,第 i 个烽火台的高度记为 $a_i$。
守卫们需要按照一定的策略将这 n 个烽火台划分成 k 组,每一组包含若干连续的烽火台(至少一个)。每一组烽火台能带来的防御值定义为该组烽火台内的最高高度和最低高度之差,守卫们当然想使得划分后能带来最大的防御值之和。
你需要帮守卫们计算对于每一个 k=1,2,...,n,最大的防御值之和是多少。
【输入】
第一行一个整数 n,表示烽火台的个数。
第二行 n 个整数 $a_1,a_2,...,a_n$,分别表示这 n 个烽火台的高度。
【输出】
输出 n 行,第 i 行输出一个整数,表示在 k=i 时最大的防御值。
【样例输入1】
```
5
1 2 3 4 5
```
【样例输出1】
```
4
3
2
1
0
```
【样例输入2】
```
5
1 2 1 2 1
```
【样例输出2】
```
1
2
2
1
0
```
【数据范围】
对于20%的数据,1<=n<=200
对于50%的数据,1<=n<=400
对于100%的数据,1<=n<=10000,1<=a_i<=10^5
思路
代码实现
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#define maxn 10005
#define inf 1e9
using namespace std;
int n;
int a[maxn];
int f[maxn][maxn];
int main(){
freopen("GreatWall.in","r",stdin);
freopen("GreatWall.out","w",stdout);
int i,j,k;
cin>>n;
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=n;i++){
for(j=1;j<=i;j++){
int Max=a[i],Min=a[i];
for(k=i-1;k>=j-1;k--){
f[i][j]=max(f[i][j],f[k][j-1]+Max-Min);
Max=max(Max,a[k]);
Min=min(Min,a[k]);
}
}
}
for(i=1;i<=n;i++)printf("%d\n",f[n][i]);
}
收获
这个动态规划搞崩我,真的不会
#### T4 照相
毕业季来了,同学们都忙着拍纪念照。
班上总共有 n 个同学,他们依次具有 1-n 的编号,并且 i 号同学的高度是 $h_i$。他们想要先在校门口拍照,以及在其它 q 个具有纪念意义的地方拍照。对于每一个地方,这 n 个同学会以一个已知的顺序依次到达。并且为了能够得到尽可能多的个人参与度,每到达一个同学就会拍一张照片,所以每一个地方都会拍 n 张照片。在一个地方拍完这 n 张照片后,同学们出发前往下一个地点继续拍照。
为了确保有序性,在照每一张照片的时候,参与的同学们总是按照编号从小到大的顺序站成一排。同时,一张照片的有序值被定义为所有相邻两同学身高之差的平方之和。你的任务是,对于每一个地点,求出在该地点的 n 张照片的有序值之和。
【输入】
第一行两个整数,n,q,分别表示学生的个数和有纪念意义的地点个数。
第二行包含 n 个整数,$h_1,h_2,...,h_n$,分别表示这 n 个同学的身高。
第三行包含 n 个整数(1-n的一个排列),$p_1,p_2,...,p_n$,表示同学们在校门口的到达顺序,$p_i$表示第 i 个到达校门口的同学编号。
在接下来的 q 行中,每一行包含一个整数 k,表示同学们到达该地点的顺序为到达上一个地点的顺序向左轮转 (k+lastans) 次,lastans 表示在上一个地点拍的 n 张照片的有序值之和。
注意:顺序$p_1,p_2,...,p_n$向左轮转一次得到的顺序是$p_2,p_3,...,p_n,p_1$。
【输出】
输出 q+1 行,第 i 行输出在第 i 个地方拍的 n 张照片的有序值之和,第一个地方是校门口。
【样例输入1】
```
5 4
1 2 3 4 5
1 2 3 4 5
6
6
8
10
```
【样例输出1】
```
10
10
13
21
36
```
【样例1解释】
对于样例1,在每个地点的学生到达顺序依次为:
[1,2,3,4,5] -> [2,3,4,5,1] -> [3,4,5,1,2] -> [4,5,1,2,3] -> [5,1,2,3,4]
【数据范围】
对于30%的数据,1<=n<=100,1<=q<=100
对于另30%的数据,1<=n<=100000,1<=q<=10
对于100%的数据,1<=n<=100000,1<=q<=100,1<=h_i<=10^4,0<=k<=10^9
思路
代码实现
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<set>
#define maxn 100005
#define ll long long
using namespace std;
int n,t;
int h[maxn],p[maxn],a[maxn]; //h[i]:i鍙蜂汉鐨勯珮搴? p[i]:鍒濆鎺掑垪涓i涓汉鐨勭紪鍙? a[i]:i鍙蜂汉杩涘叆闃熷垪鐨勬椂闂?
ll solve(int pos){
set<int> S;
int i,j,k,l,r,id;
ll ans=0,temp=0;
S.insert(p[pos]);
set<int>::iterator it;
for(i=1;i<n;i++){
pos++;if(pos>n)pos-=n;
id=p[pos];
it=S.lower_bound(id);
if(it==S.begin()){
r=*it;
temp+=1ll*(h[id]-h[r])*(h[id]-h[r]);
}
else if(it==S.end()){
it--;
l=*it;
temp+=1ll*(h[id]-h[l])*(h[id]-h[l]);
}
else {
r=*it;
it--;
l=*it;
temp+=(2ll*h[id]*h[id]-2ll*(h[l]*h[id]+h[r]*h[id]-h[l]*h[r]));
}
ans+=temp;
S.insert(id);
}
return ans;
}
int main(){
freopen("Photo.in","r",stdin);
freopen("Photo.out","w",stdout);
int i,j,k,pos=1;
ll ans;
cin>>n>>t;
for(i=1;i<=n;i++)scanf("%d",&h[i]);
for(i=1;i<=n;i++)scanf("%d",&p[i]);
ans=solve(pos);
printf("%lld\n",ans);
while(t--){
scanf("%d",&k);
pos+=(ans+k)%n;
if(pos>n)pos-=n;
ans=solve(pos);
printf("%lld\n",ans);
}
}
/*
5 4
1 2 3 4 5
1 2 3 4 5
6
6
8
10
*/
收获
新思路
小结
没有小结,直接崩溃,手撸代码的时候还没开空调,快热死了