t1:题目链接:扫雷 - 题目 - Daimayuan Online Judge
前置知识:
- 二维坐标压缩为一维坐标:将(x,y)最大值+1看成n进制,那么坐标(x,y)就可以化为x*n+y(一维)
- 哈希函数:将一个一个long long的值可以转化为一个int类型的操作(这个题好像只能用手写哈希函数转化,据说会比unordered快好几倍,用unordered_map好像时间复杂度上过不了unordered_map)
思路:
首先这个地图上可能会有重合的地雷,用并查集历遍也不行(需要对各个点之间建边,而且这个图中的边是有向的,(在有包含情况下)总是从半径大的雷指向半径小的雷),由于x,y<=1e9,如果采用二维坐标存图显然是不行的,这个时候需要将坐标压缩为一维(坐标变成了 long long),然后用哈希函数(总的点数的倍数越大越好,但也不能超过限度)将long long 的数据对应为Int 数据。
对于出现在同一个点的地雷可以用一个cnt[]数组记录下该点的总雷数,然后爆炸半径取这个点地雷中最大的。
最后,由于r<10用一个dfs或bfs历遍整个图就可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
//手写哈希表+图的历遍
const int M=999997,b=1e9+1;
//M是哈希值(M=N*10),N是存的地雷的个数,b是将二维坐标转化为一位坐标的进制
int n,m,r[M];//记录该点的爆炸半径
ll h[M];//存哈希表,必须开long long,因为二维转化后的一维坐标是long long
int ans,cnt[M];//ans记录答案,cnt[i]记录该点的地雷数
ll get_key(int x,int y){//将二维坐标转换为一维的long long
return (ll)x*b+y;
}
//手写hash函数
int find(int x,int y){//将一维坐标转化为唯一int类型
ll key=get_key(x,y);
int t=(key%M+M)%M;//加M的原因防止下标是负数
while(h[t]!=-1&&h[t]!=key){
if(++t==M)t=0;//越界了,重新从0开始
}
return t;
}
int s(int x){return x*x;}
void dfs(int x,int y,int l){
//由于搜圆不好搜
//先对中心为x,y,边长为2l的矩形进行搜索,排除圆以外的
for(int i=x-l;i<=x+l;i++){
for(int j=y-l;j<=y+l;j++){
if(cnt[find(i,j)]&&s(i-x)+s(j-y)<=s(l)){//搜寻有雷的点以及圆形内的点
ans+=cnt[find(i,j)];
cnt[find(i,j)]=0;//这个点已经搜索过了,将这个点的雷清空
dfs(i,j,r[find(i,j)]);
}
}
}
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof(h));//初始化哈希表
for(int i=1;i<=n;i++)
{
int x,y,R;
scanf("%d%d%d",&x,&y,&R);
ll t=get_key(x,y);
h[find(x,y)]=t;
cnt[find(x,y)]++;//统计该点地雷数
r[find(x,y)]=max(r[find(x,y)],R);//该点爆炸半径取最大的
}
for(int i=1;i<=m;i++){
int x,y,R;
scanf("%d%d%d",&x,&y,&R);
dfs(x,y,R);
}
cout<<ans<<endl;
return 0;
}
T2:修减灌木http://oj.daimayuan.top/course/18/problem/750
找规律:
对于3棵树的情况: 4 2 4
对于4棵树的情况: 6 2 2 6
对于5棵树的情况: 8 6 4 6 8
。。。。。。。
好成功找到了规律:对于第i棵树(i<=n/2):(n-i),然后关于中间棵树对称
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
cout<<max(n-i,i-1)*2<<endl;//规律
}
return 0;
}
T3:X进制减法X 进制减法 - 题目 - Daimayuan Online Judge
这道题很明显的贪心策略:
对于每一位的数字a和b,想要最后x-y最小,显然要每一位的进制都是最小,才能使x-y最小,故每一位的进制取max(a,b)+1,然后特判一下小于1的情况,让它是二进制;
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1000000007;
int n,a,b;
int x[1000005],y[100005],num[100005];
int main()
{
cin>>n;
cin>>a;
for(int i=a-1;i>=0;i--)cin>>x[i];
cin>>b;
for(int i=b-1;i>=0;i--)cin>>y[i];
int m=max(a,b);
for(int i=m-1;i>=0;i--){
num[i]=max(x[i]+1,y[i]+1);//贪心
num[i]=max(num[i],2);//特判一下小于2的情况
}
ll s=0;
for(int i=m-1;i>=0;i--){
s=(s*num[i]+x[i]-y[i])%mod;
}
cout<<s<<endl;
return 0;
}
T4:积木画积木画 - 题目 - Daimayuan Online Judge
状态转移:f[i]=2*f[i-1]+f[i-3](n>=3)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX=1e7+5,mod=1e9+7;
int n;
long long f[MAX],g[MAX];
int main()
{
cin>>n;
f[1]=1;f[2]=2;f[3]=5;
for(int i=4;i<=n;i++){
f[i]=(2*f[i-1]+f[i-3])%mod;
}
cout<<f[n]<<endl;
return 0;
}