T1:统计数字
考察知识:快速排序,map的基本操作
算法难度:XX || X 实现难度:XX || X+
分析:如果用快排的话,要用分治思想,难度稍微大一些,用map就是基本操作,难度不大
如果追求速度可以写一个快速输入函数,但是注意输入是否有负数
map版代码(含快速输入):
#include<cstdio>
#include<map>
#include<cctype>
using namespace std;
int T;
char ch;
void scan(int& in_){
T=1,ch=getchar();
while(!isdigit(ch)) {
if(ch=='-') T=-1;
ch=getchar();
} in_=0;
while(isdigit(ch)) in_=in_*10+ch-'0',ch=getchar();
in_*=T;
}
map<int,int>mp;
map<int,int>::iterator it;
int n,k;
int main(){
scan(n);
while(n--) scan(k),mp[k]++;
for(it=mp.begin();it!=mp.end();it++)
printf("%d %d\n",it->first,it->second);
return 0;
}
T2:字符串的展开
考察知识:字符串,模拟
算法难度:XX 实现难度:XXX
分析:按照题目说的来就可以了,但是要注意审题,要考虑全面,如:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
char str[105];
int p1,p2,p3;
int main(){
scanf("%d%d%d",&p1,&p2,&p3);
scanf("%s",str);
for(int i=0;str[i]!='\0';i++)
if(str[i]=='-'&&i&&str[i+1]!='\0'&&str[i-1]<str[i+1]){//条件要考虑全
if((isalpha(str[i+1])^isalpha(str[i-1]))||
str[i+1]=='-'||str[i-1]=='-')//注意异或
{putchar('-');continue;}
if(p3==1){
for(int j=str[i-1]+1;j<str[i+1];j++)
for(int k=1;k<=p2;k++)
if(p1==1) putchar(tolower(j));
else if(p1==2) putchar(toupper(j));
else putchar('*');
}else{
for(int j=str[i+1]-1;j>str[i-1];j--)
for(int k=1;k<=p2;k++)
if(p1==1) putchar(tolower(j));
else if(p1==2) putchar(toupper(j));
else putchar('*');
}
}
else putchar(str[i]);
return 0;
}
T3:矩阵取数游戏
考察知识:高精度,区间型动态规划
算法难度:XX 实现难度:XXX
分析:
读懂题意后我们发现我们可以把矩阵拆分成n排,每排m个元素的序列,然后针对每一排序列用动态规划:
1.定义f(curi,j)表示第cur排序列[i,j]取数的最大值
2.边界:
3.答案
4.状态转移方程:
因为最后的答案很大,使用要用高精度
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct bign{
int a[200],len;
bign(){a[0]=0,len=1;memset(a,0,sizeof(a));}
void get_v(int v){
bign(); if(!v) return; len=0;
while(v) a[len++]=v%10,v/=10;
}
friend bool operator < (bign A,bign B){
if(A.len!=B.len) return A.len<B.len;
for(int i=A.len-1;i>=0;i--) if(A.a[i]!=B.a[i])
return A.a[i]<B.a[i];
return false;
}
friend bign operator + (bign A,bign B){
bign C;
C.len=max(A.len,B.len)+1;
for(int i=0;i<C.len;i++) C.a[i]=A.a[i]+B.a[i];
for(int i=0;i<C.len;i++) if(C.a[i]>9) C.a[i+1]++,C.a[i]-=10;
while(C.len>1&&C.a[C.len-1]==0) C.len--;
return C;
}
friend bign operator * (bign A,int x){
bign C;
C.len=A.len+20;
for(int i=0;i<C.len;i++) C.a[i]=A.a[i]*x;
for(int i=0;i<C.len;i++)
if(C.a[i]>9) C.a[i+1]+=C.a[i]/10,C.a[i]%=10;
while(C.a[C.len-1]==0&&C.len>1) C.len--;
return C;
}
friend bign operator * (bign A,bign B){
bign C;C.len=A.len+B.len;
for(int i=0;i<A.len;i++)
for(int j=0;j<B.len;j++)
C.a[i+j]+=A.a[i]*B.a[j];
for(int i=0;i<C.len;i++) if(C.a[i]>9) C.a[i+1]+=C.a[i]/10,C.a[i]%=10;
while(C.len&&C.a[C.len-1]==0) C.len--;
return C;
}
void out(bool Entr=true){
for(int i=len-1;i>=0;i--) putchar('0'+a[i]);
if(Entr) putchar('\n');
}
}ans,f[82][82],b[82];
int n,m,a[100][100];
void calc(int cur){
for(int i=1;i<=m;i++) f[i][i]=b[m]*a[cur][i];
for(int len=2;len<=m;len++)
for(int i=1;i<=m-len+1;i++){
int j=len+i-1;
f[i][j]=max(f[i+1][j]+b[m-j+i]*a[cur][i],f[i][j-1]+b[m-j+i]*a[cur][j]);
}
ans=ans+f[1][m];
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
b[0].get_v(1);
for(int i=1;i<=m;i++) b[i]=b[i-1]+b[i-1];//预处理2^i
for(int i=1;i<=n;i++) calc(i);
ans.out();
return 0;
}
T4:树网的核
考察知识:树的基本知识,树的直径,枚举
算法难度:XXX 实现难度:XXX+
分析:题目有点乱,定义有点多,但是这道题并不难,根据题目的定义枚举可能的端点并计算偏心距就可以了
算法:
1.先找树的一条直径
2.计算直径上的每一个点到树的分支(不包含直径)的最大距离
3.枚举直径上所有距离小于s的两点,计算这一段路径的偏心距,偏心距=max(两点到直径端点(不经过这段路径)的距离,路径上每一点到这一点所在树的分支的最大距离)
参考代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=305;
struct edge{
int to,l,next;
}e[maxn*2];
int first[maxn],np;
void add(int u,int v,int l){
e[++np]=(edge){v,l,first[u]};
first[u]=np;
}
int n,s,A,B,dis[maxn],dis2[maxn],fa[maxn];
bool vis[maxn];
void dfs(int i,int F,int dist,int& R){
if(dist>dis[R]) R=i;
dis[i]=dist,fa[i]=F;
for(int p=first[i];p;p=e[p].next){
int j=e[p].to;
if(j==F) continue;
dfs(j,i,dist+e[p].l,R);
}
}
void dfs2(int i,int dist,int rt){
vis[i]=true;
dis2[rt]=max(dis2[rt],dist);
for(int p=first[i];p;p=e[p].next){
int j=e[p].to;
if(!vis[j]) dfs2(j,dist+e[p].l,rt);
}
}
void build(){
int u,v,l;
scanf("%d%d",&n,&s);
for(int i=1;i<n;i++){
scanf("%d%d%d",&u,&v,&l);
add(u,v,l),add(v,u,l);
}
dfs(1,0,0,A=0);//找直径
dfs(A,0,0,B=0);
for(int i=B;i;i=fa[i]) vis[i]=true;
for(int i=B;i;i=fa[i]) dfs2(i,0,i);//计算分支最大距离
}
int ans=0xffffff;
void solve(){
for(int i=B;i;i=fa[i])//枚举
for(int j=i;j;j=fa[j]) if(dis[i]-dis[j]<=s){
int T=max(dis[j],dis[B]-dis[i]);
for(int k=i;;k=fa[k]){//计算偏心距
T=max(T,dis2[k]);
if(k==j) break;
}
ans=min(ans,T);
}
else break;
printf("%d\n",n==1?0:ans);
}
int main(){
build();
solve();
return 0;
}