上午:
第一题:回文图
题目描述
输入
输出
样例输入
(如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
4 2 3
1 1
3 1
样例输出
3
提示
0<=n<=10000,0<=m<=2000,0<=k<=1000000
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
const int N=10000+10;
const long long mod=100000007;
int n,m,x,y;
long long k,tot,f[N];
map<pair<int,int>,bool > flag;
void work(int i,int j){
if(flag[make_pair(i,j)]==1) return ;
flag[make_pair(i,j)]=flag[make_pair(i,n-j+1)]=
flag[make_pair(n-i+1,j)]=flag[make_pair(n-i+1,n-j+1)]=
flag[make_pair(j,i)]=flag[make_pair(n-j+1,i)]=
flag[make_pair(j,n-i+1)]=flag[make_pair(n-j+1,n-i+1)]=1;
tot++;
}
long long qpow(long long tmp,long long p){
long long res=1LL;
while(p){
if(p&1) res=res*tmp%mod;
p>>=1,tmp=tmp*tmp%mod;
}
return res;
}
int main(){
scanf("%d %d %lld",&n,&m,&k);
f[1]=f[2]=1LL;
for(int i=3;i<=n;i++)
f[i]=((i+1)>>1LL)+f[i-2];
for(int i=1;i<=m;i++){
scanf("%d %d",&x,&y);
work(x+1,y+1);
}
printf("%lld\n",qpow(k,f[n]-tot));
}
成绩:AC
分析:其实就一个大水题,虽然最后A了,然而读题时读了很久o(╯□╰)o,对于翻转的理解开始想了很久。。尴尬O__O"…
第二题:体检
题目描述
开学了,学校要求你进行入学体检。
你到了校医务室门口,发现有好多学生在排队,人数还在不断增加。
有多个体检项目要做。每个项目都有很多人在排队。队伍的长度在随着时间变长。该选哪一个队伍排队呢?这成了一个问题。你要安排一下体检顺序,尽可能早的完成所有项目的体检。
输入
第一行一个整数n,表示要体检的项目数量
接下来n行,每行表示一个体检项目。每行两个整数a和b,描述该项目的情况:
1.如果你在第0时刻加入了这只队伍,需要等待a秒钟才能完成该项目的检查。
2.当你不在这个队伍里,随时间队伍会变得越来越长,等待的时间每秒钟会增加b秒。
输出
一个整数表示你完成体检最短需要花费的时间。
结果可能很大,所以请mod (365×24×60×60)再打印出结果
对于50%的数据有:0<n<=1000 0<=a,b<=30000
对于100%的数据有:0<n<=100000 0<=a,b<=50000
样例输入
(如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
5
1 2
2 3
3 4
4 5
5 6
样例输出
1419
提示
你按以下次序体检.
1.在第一个队伍中花了1秒
2.在第二个队伍中花了5秒
3.在第三个队伍中花了27秒
4.在第四个队伍中花了169秒
5.在第五个队伍中花了1217秒
所以总时间是1419秒
所以按a/b从小到大排序。O(∩_∩)O~~
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100000+10;
const int mod=365*24*60*60;
struct node{
long long a,b;
bool operator < (const node &x)const{
return a*x.b<b*x.a;
}
}arr[N];
int n;
long long ans;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld %lld",&arr[i].a,&arr[i].b);
sort(arr+1,arr+n+1);
for(int i=1;i<=n;i++)
ans=((ans+arr[i].a)%mod+arr[i].b*ans%mod)%mod;
printf("%lld\n",ans);
}
成绩:AC
分析:整场考试做的最顺的一道题,毕竟前几天才练了类似的贪心题
第三题:龙珠雷达
题目描述
你得到了一个龙珠雷达,它会告诉你龙珠出现的时间和地点。
龙珠雷达的画面是一条水平的数轴,每一个窗口时间,数轴的某些点上会出现同一种龙珠,每当你获得其中一颗龙珠,其它龙珠就会消失。下一个窗口时间,数轴上又会出现另一种龙珠。总共有n个窗口时间,也就是总共有n种龙珠。
假设你会瞬间移动,你从数轴的x点移动到y点,耗时0秒,但是需要耗费|x-y|的体力。同时,挖出一颗龙珠也需要耗费一定的体力。请问,最少耗费多少体力,就可以收集齐所有种类的龙珠。
输入
第一行,三个整数n,m,x,表示共有n个窗口时间,每个窗口时间会出现m个龙珠,x是一开始你所处的位置。
接下来有两个n*m的矩阵。
对于第一个矩阵,坐标为(i,j)的数字表示第i个窗口时间,第j个龙珠的位置。
对于第二个矩阵,坐标为(i,j)的数字表示第i个窗口时间,挖取第j个龙珠所需的体力。
输出
一个整数,表示所需最小体力
样例输入
(如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
3 2 5
2 3
4 1
1 3
1 1
1 3
4 2
样例输出
8
提示
所有数据均为整数
数轴范围在0到30000
挖一颗龙珠所需体力不超过30000
结果保证在int范围
对于50%的数据,1<=n<=50,1<=m<=500。
对于100%的数据,1<=n<=50,1<=m<=5000。
题解:(⊙o⊙)…,这道题是很明显的dp,方程式也很好想dp[i][j]表示i时刻站在位置j(有龙珠)上的最小体力。
dp[i][pos[j]]=min(dp[i-1][pos[k]]+abs(pos[j]-pos[k])+w[i][j]),重点在于优化,其实优化也是很好想的,abs展开后,用两个单调队列分别dp[i-1][pos[k]]-pos[k]和dp[i-1][pos[k]]+pos[k],重点在于写的时候顺序很恶心,维护dp[i-1][pos[k]]-pos[k]时需要倒过来,防止一些pos较大但更优的值被较小的j误弹。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<deque>
using namespace std;
const int N=50+10;
const int M=5000+10;
const int L=30000+10;
const int inf=0x3f3f3f3f;
struct node{
int num,pos;
node(){}
node(int a,int b){
num=a,pos=b;
}
}now;
deque<node> Fron;
deque<node> Bac;
struct Node{
int pos,w;
bool operator < (const Node &a)const{
return pos<a.pos;
}
}arr[N][M];
int n,m,start;
int dp[N][L];
int main(){
scanf("%d %d %d",&n,&m,&start);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&arr[i][j].pos);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
scanf("%d",&arr[i][j].w);
sort(arr[i]+1,arr[i]+m+1);
}
memset(dp,0x3f,sizeof dp);
dp[0][start]=0,arr[0][1].pos=start;
for(int i=1;i<=n;i++){
Fron.clear();
Bac.clear();
for(int j=1;j<=m;j++){
//if(i==1&&j>1) break ;
now=node(dp[i-1][arr[i-1][m-j+1].pos]-arr[i-1][m-j+1].pos,arr[i-1][m-j+1].pos);
while(!Fron.empty()&&Fron.back().num>now.num)
Fron.pop_back();
Fron.push_back(now);
now=node(dp[i-1][arr[i-1][j].pos]+arr[i-1][j].pos,arr[i-1][j].pos);
while(!Bac.empty()&&Bac.back().num>now.num)
Bac.pop_back();
Bac.push_back(now);
}
for(int j=1;j<=m;j++){
while(!Fron.empty()&&Fron.front().pos>arr[i][m-j+1].pos)
Fron.pop_front();
if(!Fron.empty())
dp[i][arr[i][m-j+1].pos]=min(dp[i][arr[i][m-j+1].pos],Fron.front().num+arr[i][m-j+1].pos+arr[i][m-j+1].w);
while(!Bac.empty()&&Bac.front().pos<arr[i][j].pos)
Bac.pop_front();
if(!Bac.empty())
dp[i][arr[i][j].pos]=min(dp[i][arr[i][j].pos],Bac.front().num-arr[i][j].pos+arr[i][j].w);
}
}
int ans=inf;
for(int i=1;i<=L;i++)
ans=min(ans,dp[n][i]);
printf("%d\n",ans);
}
/*
3 2 5
2 3
4 1
1 3
1 1
1 3
4 2
*/
成绩:AC
分析:单调队列不是很熟,写时还是调了一会,其实当时聪明一点写线段树可能反而节省更多时间。
总结:虽然第一题读了半天题但最后还是难得的AK了一次~\(≧▽≦)/~啦啦啦,不过说真的,如果不是别人提醒了一下,第一题还真不知道最后会怎么样。。O__O"…23333333333333