题目考察范围及做法一览
6445: 小z游东湖 if或ceil函数
6455: 学学学 状压DP
6447: 小z的零花钱 一重循环
6470: 小z与他的袜子 思维找循环节or数组模拟状态
6466: 小z买文具 一重循环
6467: 小z的家庭作业 简单数组
6449: 小z与直角三角形 两重循环
6469: 小z的遥控车 搜索
6468: 小z的班级平时分 多维数组+字符串比较
6451: levil与因子和 数论
6454: 乐呵采蘑菇 贪心
6450: levil与时间点 STL
6471: 小z的迷宫游戏 广搜或tarjan或者处理过的拓扑排序
简单题:小z游东湖、小z的零花钱 、小z买文具、小z与直角三角形、小z的家庭作业、小z的班级平时分(不太准)
中等题:小z与他的袜子(不太准)、小z的遥控车(不太准)、乐呵采蘑菇、levil与时间点
难题:levil与因子和、小z的迷宫游戏、学学学
1.6445: 小z游东湖
选择大船需要的条数少,直接/6得到的是商不包含余数,可以判断一下是否有余数也可以用ceil进行向上取整
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x;
cin>>x;
cout<<(int)ceil(x/6.0);
}
也可以直接把它+5再➗6,这样多1~5个人都会多一条船,恰好够不多船
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a;
cin>>a;
cout<<(a+5)/6<<"
";
return 0;
}
2.6455: 学学学
这类数据量这么小的往往都可以使用状压DP去实现
儿子排好序后父节点才会访问,我们定义二进制上为1代表这个点已经访问过,即参与过排序
父节点均可以由子节点转移而来,我们可以用son来表示转移的合法状态,用dp进行统计,二进制全为1即所有算法都学了
这个过程中属于加法原理
#include<stdio.h>
#include<string.h>
using namespace std;
#define ll long long int
int n,m;
ll dp[(1<<19)];
int son[19];
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
x--;y--;
son[x]|=(1<<y);
}
int end=(1<<n);
dp[0]=1;
for(int i=0;i<end;i++)
{
if(dp[i]>0)
{
for(int j=0;j<n;j++)
{
if((i&(son[j]))==son[j])
{
if((i&(1<<j))==0)
{
dp[(i|(1<<j))]+=dp[i];
}
}
}
}
}
printf("%I64d
",dp[end-1]);
return 0;
}
3.6447: 小z的零花钱
我们可以一重循环模拟下他的零花钱,设置两个变量,1个为今天拿到的钱,还有总钱,比较简单。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,k;
cin>>n>>k;
int sum=0,t=0;
for(int i=0;i<n;i++)
{
if(i%k==0)t++;
if(t>5)t=5;
sum+=t;
}
cout<<sum<<"
";
return 0;
}
4.6470: 小z与他的袜子
这个是存在循环的,但是思考起来比较麻烦。我们可以考虑数组的办法。
k天,k次循环,早上找到编号最小的没穿的,也就是数组为0的拿来穿;
穿完给他标记下,当前元素变为1;
晚上看看是不是有n-1双袜子了,是的话给他洗了,给n-1双变为2;
什么时候收袜子呢,肯定要在洗之前,如果已经是2,代表昨天洗了,把它们收进来重新置0即可。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,k;
int a[1005]={0};
cin>>n>>k;
int ans;
for(int i=0;i<k;i++)
{
int flag;
for(int j=1;j<=n;j++)
{
if(a[j]==0)
{
flag=j;
break;
}
}
ans=flag;
a[flag]=1;
for(int j=1;j<=n;j++)
{
if(a[j]==2)a[j]=0;
}
int t=0;
for(int j=1;j<=n;j++)
{
if(a[j])t++;
}
if(t==n-1)
{
for(int j=1;j<=n;j++)
{
if(a[j])a[j]=2;
}
}
}
cout<<ans<<"
";
}
也可以直接找到循环的规律
#include <bits/stdc++.h>
using namespace std;
#include <cstdio>
int main()
{
int n, k, ans;
cin >> n >> k;
if (k <= n)
{
ans = k;
}
else
{
k -= n;
if (k % (n - 1))
ans = k % (n - 1);
else if ((k / (n - 1)) % 2)
ans = n - 1;
else
ans = n;
}
cout << ans;
return 0;
}
5.6466: 小z买文具
需要执行n次循环统计一下总钱数,然后再买买东西的花费减去
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
double sum=0;
for(int i=0;i<n;i++)
{
int x;
cin>>x;
sum+=x;
}
for(int i=0;i<m;i++)
{
double w;
int y;
cin>>w>>y;
sum-=w*y;
}
if(sum==0)
{
cout<<"Perfect
";
}
else if(sum<0)
{
cout<<"No";
printf(" %.1f",-sum);
}
else
{
cout<<"Yes";
printf(" %.1f",sum);
}
return 0;
}
6.6467: 小z的家庭作业
由于不知道老师的参考时间,所以作业必定需要存储下来,等到知道参考时间再统计,注意等于也属于超时
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
int a[55];
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
int sum=0;
double s;
cin>>s;
for(int i=0;i<n;i++)
if(a[i]>=s)sum++;
cout<<sum<<"
";
return 0;
}
7.6449: 小z与直角三角形
可以让第一重循环从1到z,较小者为勾,那么股需要大于勾,股可以从勾+1到z,如果等于z输出即可。
不存在可以用一个旗子标记下
#include <bits/stdc++.h>
using namespace std;
int main()
{
int z;
cin>>z;
int flag=0;
for(int i=1;i<=z;i++)
{
for(int j=i+1;j<=z;j++)
{
if(i*i+j*j==z*z)
{
cout<<i<<" "<<j<<"
";
flag=1;
}
}
}
if(!flag)
{
cout<<"None
";
}
return 0;
}
8.6469: 小z的遥控车
这题正解为BFS,因为广搜的时候可以保证步数最少,直接搜到x就可以了
#include <bits/stdc++.h>
using namespace std;
int dir[6]={1,-1,7,-7,10,-10};
int s, e;
int visited[300], step[300];
int BFS()
{
queue<int> qu;
qu.push(s);
visited[150+s] = 1;
step[150+s] = 0;
while(!qu.empty())
{
int cur = qu.front();
qu.pop();
if(cur==e)
return step[150+cur];
for(int i=0;i<6;i++)
{
int nxt = cur+dir[i];
if(abs(nxt)<=120 && visited[150+nxt]==0)
{
visited[150+nxt] = 1;
step[150+nxt] = step[150+cur]+1;
qu.push(nxt);
}
}
}
}
int main()
{
int cas;
cin>>cas;
while(cas--)
{
memset(visited, 0, sizeof(visited));
memset(step, 0, sizeof(step));
s = 0;
cin>>e;
cout<<BFS()<<endl;
}
return 0;
}
我们可以深搜记录下最小的步数
#include <bits/stdc++.h>
using namespace std;
int n, k ,t;
void dfs(int x, int s)
{
if (s >= t)
return;
if (x == n)
{
t = min(t, s);
return;
}
if (x > n)
{
dfs(x - 1, s + 1);
dfs(x - 10, s + 1);
dfs(x - 7, s + 1);
}
else
{
dfs(x + 1, s + 1);
dfs(x + 10, s + 1);
dfs(x + 7, s + 1);
}
}
int main()
{
int T;
cin >> T;
while (T--)
{
t = 123456;
cin >> n;
dfs(0, 0);
cout << t << "
";
}
return 0;
}
先贪心处理一个区间,然后直接加
#include <iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
using namespace std;
float s[50];
int main()
{
int n,jl,tot,i;
cin>>jl;
for(i=1;i<=jl;i++)
{
tot=0;
cin>>n;if(n<0)n=-n;
if(!(n%10)){tot=n/10;n=0;}
if(n>20){tot+=(n-10)/10;n=(n-10)%10+10;}
while(n)
{
if(!(n%7)){tot+=n/7;n=0;}
else
{
if(n==19)tot+=3;
if(n==18)tot+=3;
if(n==17)tot+=2;
if(n==16)tot+=3;
if(n==15)tot+=3;
if(n==13)tot+=3;
if(n==12)tot+=3;
if(n==11)tot+=2;
if(n==9)tot+=2;
if(n==8)tot+=2;
if(n==6)tot+=2;
if(n==5)tot+=3;
if(n==4)tot+=3;
if(n==3)tot+=2;
if(n==2)tot+=2;
if(n==1)tot+=1;
n=0;
}
}
cout<<tot<<endl;
}
return 0;
}
杨添盛自己动手找到了答案的表
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a[102]={1, 2, 3, 3, 3, 2, 1, 2, 2, 1,
2, 3, 3, 2, 3, 3, 2, 3, 3, 2,
3, 4, 4, 3, 4, 4, 3, 4, 4, 3,
4, 5, 5, 4, 5, 5, 4, 5, 5, 4,
5, 6, 6, 5, 6, 6, 5, 6, 6, 5,
6, 7, 7, 6, 7, 7, 6, 7, 7, 6,
7, 8, 8, 7, 8, 8, 7, 8, 8, 7,
8, 9, 9, 8, 9, 9, 8, 9, 9, 8,
9, 10, 10, 9, 10, 10, 9, 10, 10, 9,
10, 11, 11, 10, 11, 11, 10, 11, 11, 10
};
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
n=abs(n);
if(n==0) cout<<0<<"
";
else cout<<a[n-1]<<"
";
}
return 0;
}
9.6468: 小z的班级平时分
这个题是比较简单,我们二维数组存储下,然后就是找最大值和最小值,我们记录下下标就可以,代码是有点长,但是写起来还是容易的
原标程有bug,现已更换。感谢Ycp
#include <bits/stdc++.h>
using namespace std;
char s[15][15][25];
int a[15][15];
int main()
{
int n,m;
while(cin>>n>>m)
{
int mini=1,minj=1;
int maxi=1,maxj=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>s[i][j];
if(strcmp(s[i][j],"None"))
{
mini=i,minj=j;
maxi=i,maxj=j;
}
}
}
memset(a,0,sizeof(a));
int q;
cin>>q;
while(q--)
{
int op,x,y;
cin>>op>>x>>y;
if(op==1)
{
a[x][y]-=5;
}
else
{
a[x][y]+=3;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(strcmp(s[i][j],"None"))
{
if(a[i][j]<a[mini][minj])
{
mini=i;
minj=j;
}
if(a[i][j]==a[mini][minj]&&strcmp(s[i][j],s[mini][minj])<0)
{
mini=i;
minj=j;
}
if(a[i][j]>a[maxi][maxj])
{
maxi=i;
maxj=j;
}
if(a[i][j]==a[maxi][maxj]&&strcmp(s[i][j],s[maxi][maxj])<0)
{
maxi=i;
maxj=j;
}
}
}
}
cout<<s[maxi][maxj]<<" "<<a[maxi][maxj]<<"
";
cout<<s[mini][minj]<<" "<<a[mini][minj]<<"
";
}
return 0;
}
10.6451: levil与因子和
考虑每个数的倍数会在这个区间中出现几个,然后再乘上每个数即可(也就是一个个计算每个数的贡献)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int main()
{
int a,b;scanf("%d %d",&a,&b);
LL ans = b - a + 1;
for(int i = 2;i <= b;++i)
{
ans += (LL)(i * (b / i - (a - 1) / i));
if(i >= a && i <= b) ans -= i;
}
printf("%lld",ans);
return 0;
}
如果给你1~n的因子和会做吗,其实就是整数分块,然后最后用一个等差数列处理下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll la(int n)
{
ll sum = 0;
for (int i = 1; i <= n; ++i)
{
sum += n / i * i;
}
if (n)
{
sum -= (2 + n) * 1LL * (n - 1) / 2;
}
return sum;
}
int main()
{
int a, b;
scanf("%d%d", &a, &b);
cout << la(b) - la(a - 1) << "
";
return 0;
}
11.6454: 乐呵采蘑菇
这个题目和渊子赛马类似,我们只需要让最不浪费的人去拿蘑菇就好
也就是枚举小水潭从小开始,如果手臂半径大于小水潭那么就拿到,这样我们就可以确保以最小的去拿到,直接采摘人全部没有。
#include <bits/stdc++.h>
using namespace std;
#define N 20001
int a[N],b[N];
int main()
{
int n,m;
ios::sync_with_stdio(false);
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<n;i++)scanf("%d",&a[i]);
for(int i=0;i<m;i++)scanf("%d",&b[i]);
sort(a,a+n);
sort(b,b+m);
int i,res=0,j=0;
for(i=0;i<m;i++)
{
if(a[j]<=b[i])
{
res+=b[i];
j++;
if(j==n)break;
}
}
if(j<n)puts("Sad!");
else printf("%d
",res);
}
}
12.6450: levil与时间点
操作包含删除和插入,这种往往需要使用数据结构,STL的map是满足这个特性的,也可以使用pq记录下最大的,速度还是蛮快的
T*sqrt(a[i])会超时,所以要先离散化,过了的是水过去了
出题人的代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define dbg(ax) cout << "now this num is " << ax << endl;
const int N = 1e5 + 5;
priority_queue<int,vector<int>,less<int> > Q;//小顶堆
map<int,int> mp,yz;//map计数
struct Query{int id,y;}p[N];
int a[1005],tot = 0;
int main()
{
int T,x;scanf("%d %d",&T,&x);
Q.push(x),mp[x]++;
a[++tot] = x;
for(int i = 1;i <= T;++i)
{
scanf("%d",&p[i].id);
if(p[i].id != 1) scanf("%d",&p[i].y);
if(p[i].id == 2) a[++tot] = p[i].y;
}
sort(a + 1,a + tot + 1);
int len = unique(a + 1,a + tot + 1) - a - 1;
for(int i = 1;i <= len;++i)
{
if(a[i] == 1 || a[i] == 2 || a[i] == 3) yz[a[i]] = 1;
else
{
int m = sqrt(a[i]),ans = 1;
for(int j = 2;j <= m;++j) if(a[i] % j == 0) ans = max(ans,max(j,a[i] / j));
yz[a[i]] = ans;
}
}
for(int i = 1;i <= T;++i)
{
if(p[i].id == 1)
{
while(mp[Q.top()] == 0) Q.pop();
int mx = Q.top();
printf("%d
",yz[mx]);
}
else
{
int z = p[i].y;
if(p[i].id == 2) Q.push(z),mp[z]++;
if(p[i].id == 3) printf("%d
",mp[z]);
if(p[i].id == 4) mp[z]--;
}
}
return 0;
}
被我水过去了
#include <bits/stdc++.h>
using namespace std;
priority_queue<int> pq;
map<int, int> M;
int la(int n)
{
int x=sqrt(n+0.5);
for(int i=2;i<=x;i++)
{
if(n%i==0)return n/i;
}
return 1;
}
int main()
{
int T, x;
cin >> T >> x;
pq.push(x), M[x]++;
while (T--)
{
int op;
cin >> op;
if (op == 1)cout<<la(pq.top())<<"
";
else if(op==2)
{
cin>>x;
pq.push(x), M[x]++;
}
else if(op==3)
{
cin>>x;
if(M.count(x))
{
cout<<M[x]<<"
";
}
else
{
cout<<"0
";
}
}
else
{
cin>>x;
if(M.count(x))
{
M[x]--;
if(M[x]==0)
{
M.erase(x);
}
}
}
}
return 0;
}
13.6471: 小z的迷宫游戏
有环,而且i只会有一个Fi,那么tarjan求环即强连通分量非常不错啊
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+5;
struct graph
{
int head[maxn],nxt[maxn<<1],to[maxn<<1],w[maxn<<1],sz;
void init(){memset(head,-1,sizeof(head));}
graph(){init();}
void push(int a,int b,int c){nxt[sz]=head[a],to[sz]=b,w[sz]=c,head[a]=sz++;}
int& operator[](const int a){return to[a];}
}g;
int a[maxn],dp[maxn],dfn[maxn],low[maxn],tot,cnt;
int scc[maxn],sum[maxn];
bool instk[maxn];
bool circle[maxn];
stack<int>stk;
void tarjan(int now)
{
low[now]=dfn[now]=++tot;
stk.push(now);
instk[now]=1;
for(int i = g.head[now];~i;i = g.nxt[i]){
if(!dfn[g[i]]){
tarjan(g[i]);
low[now]=min(low[now],low[g[i]]);
}
else if(instk[g[i]]){
low[now]=min(low[now],dfn[g[i]]);
}
}
if(low[now]==dfn[now]){
int u,c;
c=0;
cnt++;
do{
c++;
u = stk.top(),stk.pop();
scc[u]=cnt,sum[cnt]+=a[u];
instk[u]=0;
}while(u!=now);
if(c>1){
circle[cnt]=1;
}
}
}
int dfs(int x)
{
int now = scc[x];
if(circle[now])return sum[now];
if(dp[now])return dp[now];
dp[now]=sum[now];
for(int i = g.head[x];~i;i = g.nxt[i]){
dp[now]+=dfs(g[i]);
}
return dp[now];
}
int main()
{
int n;
scanf("%d",&n);
for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
for(int i = 1,b;i <= n;++i){
scanf("%d",&b);
if(b!=i)
g.push(i,b,0);
}
for(int i = 1;i <= n;++i){
if(!dfn[i])tarjan(i);
}
for(int i = 1;i <= n;++i){
printf("%d
",dfs(i));
}
return 0;
}
同一关卡刷多次不算分,但是这个图仅仅会是多个环带上几个链,所以不会走两次就能多刷一关,所以每个点仅访问一次
我们可以拓扑排序,把它放进栈里,因为栈先进后出,后进先出,我们可以得到后来的F[i]的答案再去更新i的答案
#include<bits/stdc++.h>
using namespace std;
const int N=200005;
queue<int> q;
stack<int> S;
int n;
int d[N], f[N], e[N], ans[N];
bool vis[N];
void Top_sort()
{
for (int i = 1; i <= n; i++)
if (!d[i])
q.push(i);
while (!q.empty())
{
int t = q.front();
q.pop();
S.push(t);
d[f[t]]--;
if (!d[f[t]])
q.push(f[t]);
}
}
void dfs(int u, int root)
{
if (vis[u])
return;
vis[u] = 1;
ans[root] += e[u];
q.push(u);
dfs(f[u], root);
}
void circle()
{
for (int i = 1; i <= n; i++)
if (d[i] && !vis[i])
{
dfs(i, i);
while (!q.empty())
{
int t = q.front();
q.pop();
ans[t] = ans[i];
}
}
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &e[i]);
for (int i = 1; i <= n; i++)
{
scanf("%d", &f[i]);
d[f[i]]++;
}
Top_sort();
circle();
while (!S.empty())
{
int t = S.top();
S.pop();
ans[t] = e[t] + ans[f[t]];
}
for (int i = 1; i <= n; i++)
printf("%d
", ans[i]);
return 0;
}
环上的时候就搜一下,做一下前缀和。DFS的话这个点太多会爆栈,可以使用BFS进行搜索
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 2e5 + 5;
namespace FASTIO{
inline LL read(){
LL x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
return x*f;
}
}
using namespace FASTIO;
int n,a[N],fa[N];
LL ans[N][2];
bool vis[N];
vector<int> vec;
void solve(int st)
{
int pre = st;
vis[st] = 1;
ans[st][0] = a[st];
vec.push_back(st);
while(1)
{
int u = fa[pre];
LL ma = ans[pre][0] + a[u];
pre = u;
if(vis[u])
{
if(ans[u][0] == -1)
{
for(auto v : vec) ans[v][1] = ma - ans[v][0] + a[v] - a[u] + ans[u][1];
}
else
{
ans[u][1] = ma - ans[u][0];
for(auto v : vec)
{
if(v == u) continue;
if(ans[v][0] < ans[u][0]) ans[v][1] = ans[u][0] - ans[v][0] - a[u] + a[v] + ans[u][1];
else ans[v][1] = ans[u][1];
}
}
for(auto v : vec) ans[v][0] = -1;
vec.clear();
return ;
}
vis[u] = 1;
vec.push_back(u);
ans[u][0] = ma;
}
}
int main()
{
n = read();
for(int i = 1;i <= n;++i) a[i] = read(),ans[i][0] = -1;
for(int i = 1;i <= n;++i) fa[i] = read();
for(int i = 1;i <= n;++i)
{
if(!vis[i]) solve(i);
}
for(int i = 1;i <= n;++i) printf("%lld
",ans[i][1]);
return 0;
}