做题笔记(一)
Sort Left and Right
题目传送门
题目大意
给定关于
思路
其实是一个小结论题,赛时智障写了 30min。
首先发现,如果
然后可以考虑遍历一下
如果
值得一提的是,当排列为
时间复杂度
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,a[200001];
bool v[200001]={0};
int pos;
void solve(){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
pos=0;
for(int i=1;i<=n;i++)
v[i]=0;
bool f=1;
for(int i=1;i<=n;i++){
if(a[i]!=i){
f=0;
break;
}
}
if(f){
cout<<0<<endl;
return;
}
if(a[1]==n&&a[n]==1){
cout<<3<<endl;
return;
}
for(int i=1;i<=n;i++){
while(v[pos+1]&&pos<n)
pos++;
if(a[i]==i){
if(pos>=i-1){
cout<<1<<endl;
return;
}
}
v[a[i]]=1;
}
cout<<2<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int t; cin>>t;
while(t--) solve();
return 0;
}
Distinct Characters Queries
题目传送门
题目大意
给定一个字符串
-
给出
,将 改成 。 -
给出
,求 中不同字符的种类个数。
思路
其实挺水的,但是考场上不一定会写这种做法。
给出一个数组
对于每一次更改,就是把
显然地,区间加单点查,线段树和树状数组都可以做。
这时肯定很多人就想这道题用数据结构肯定不是正解!一定有更优秀的解法。
其实不是的,这道题的正解就是数据结构。
时间复杂度
代码
代码没写咕咕咕。
满汉全席
题目传送门
题目大意
题意过长无法概括咕咕咕。
思路
这应该可以算省选送分题。
根据所有评审员的要求(限制),我们发现这是一个非常板的 2-SAT。每一个评审员的要求至少要满足一个。
所以我们可以把每一次给出的要求这样连边:
- 如果两个都是
,那么就把 连起来。
以此类推,我们得到了
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,tot=0;
vector<int>V[1000001];
int dfn[1000001]={0},low[1000001]={0};
int timer=0,belong[1000001]={0};
stack<int>s;bool instack[1000001]={0};
void tarjan(int p){
dfn[p]=++timer;low[p]=timer;
s.push(p);instack[p]=1;
for(int i=0;i<V[p].size();i++){
if(!dfn[V[p][i]]){
tarjan(V[p][i]);
low[p]=min(low[V[p][i]],low[p]);
}
else if(instack[V[p][i]])
low[p]=min(dfn[V[p][i]],low[p]);
}
if(dfn[p]==low[p]){
tot++;
while(s.top()!=p){
instack[s.top()]=0;
belong[s.top()]=tot;
s.pop();
}
instack[s.top()]=0;
belong[s.top()]=tot;
s.pop();
}
}
void solve(){
cin>>n>>m;
timer=0;tot=0;
while(!s.empty())s.pop();
for(int i=1;i<=100000;i++)V[i].clear();
for(int i=1;i<=100000;i++)
dfn[i]=0,low[i]=0,belong[i]=0,instack[i]=0;
for(int i=1;i<=m;i++){
char x,y;int a,b;
cin>>x>>a>>y>>b;
if(x=='m'&&y=='m'){
V[a+n].push_back(b);
V[b+n].push_back(a);
}
else if(x=='m'&&y=='h'){
V[a+n].push_back(b+n);
V[b].push_back(a);
}
else if(x=='h'&&y=='m'){
V[a].push_back(b);
V[b+n].push_back(a+n);
}
else{
V[a].push_back(b+n);
V[b].push_back(a+n);
}
}
for(int i=1;i<=(n<<1);i++)
if(!dfn[i])tarjan(i);
for(int i=1;i<=n;i++){
if(belong[i]==belong[i+n]){
cout<<"BAD"<<endl;
return;
}
}
cout<<"GOOD"<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int t;cin>>t;
while(t--)solve();
return 0;
}
试卷(Problem)
题目传送门
没有原题咕咕咕。
题目大意
给出
-
子矩阵种没有
。 -
子矩阵中数字的平均数为
。
思路
发现,
发现,每一个
首先把所有的
时间复杂度
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,ct=0,c3=0;
int cnt=0;
int vis[2001000]={0};
int mch[2001000]={0};
vector<int>V[100005];
bool dfs(int p,int tag){
if(vis[p]==tag) return 0;
vis[p]=tag;
for(int i=0;i<V[p].size();i++){
int to=V[p][i];
if((mch[to]==0)||dfs(mch[to],tag)){
mch[to]=p;
return 1;
}
}
return 0;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
int a[n+2][m+2];
char c[n+2][m+2];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>c[i][j];
if(c[i][j]=='3')
a[i][j]=++c3;
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if(c[i][j]=='2')
ct++;
if(c[i][j]=='1'){
cnt++;
if(c[i-1][j]=='3') V[cnt].push_back(a[i-1][j]);
if(c[i+1][j]=='3') V[cnt].push_back(a[i+1][j]);
if(c[i][j+1]=='3') V[cnt].push_back(a[i][j+1]);
if(c[i][j-1]=='3') V[cnt].push_back(a[i][j-1]);
}
}
int ans=0;
for(int i=1;i<=cnt;i++){
if(dfs(i,i)) ans++;
}
cout<<ans+ct<<endl;
return 0;
}
AtCoder Regular Contest001
センター採点
题目传送门
题目大意
给出字符串
思路
开一个桶直接跑就行,远古 arc 入门题。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n,num[5]={0}; cin>>n;
string s; cin>>s;
for(int i=0;i<n;i++){
num[s[i]-'0']++;
}
int mx=0,mn=1e17;
for(int i=1;i<=4;i++){
mx=max(num[i],mx);
mn=min(num[i],mn);
}
cout<<mx<<' '<<mn<<endl;
return 0;
}
リモコン
题目传送门
题目大意
给出
思路
估计会有人想成贪心吧,其实不是的。
比如说下面这个数据:
不妨设
-
首先对于
,有 。 -
对于第二次的 DP,我们可以假定一个上界。注意到数据范围很小,那么我们定这个上界为
,有 。
跑得挺快的。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int a,b; cin>>a>>b;
if(a>b) swap(a,b);
int f[500]={0}; f[a]=0;
for(int i=a+1;i<=100;i++){
f[i]=f[i-1]+1;
if(i-a>=5) f[i]=min(f[i-5]+1,f[i]);
if(i-a>=10) f[i]=min(f[i-10]+1,f[i]);
}
for(int i=99;i>=a;i--){
f[i]=min(f[i+1]+1,f[i]);
if(100-i>=5) f[i]=min(f[i+5]+1,f[i]);
if(100-i>=10) f[i]=min(f[i+10]+1,f[i]);
}
cout<<f[b]<<endl;
return 0;
}
パズルのお手伝い
题目传送门
题目大意
给一个已经填了
思路
八皇后啊,搜索经典板题。
DFS 即可,不知道为什么评 黄
。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
bool vis[15][15]={0};
char c[15][15]={0};
void dfs(int k,int a,int b){
if(k>5){
for(int i=1;i<=8;i++){
for(int j=1;j<=8;j++)
cout<<c[i][j];
cout<<endl;
}
exit(0);
}
int g[15][15];
for(int i=1;i<=8;i++)
for(int j=1;j<=8;j++)
g[i][j]=vis[i][j];
for(int i=a;i<=8;i++){
for(int j=(i==a?b:1);j<=8;j++){
if(vis[i][j]) continue;
c[i][j]='Q';
for(int k=1;k<=8;k++){
vis[i][k]=1;
vis[k][j]=1;
}
for(int k=1;k<=8;k++){
vis[i-k][j-k]=1;
if(i-k==0||j-k==0)
break;
}
for(int k=1;k<=8;k++){
vis[i+k][j+k]=1;
if(i+k==8||j+k==8)
break;
}
for(int k=1;k<=8;k++){
vis[i-k][j+k]=1;
if(i-k==0||j+k==8)
break;
}
for(int k=1;k<=8;k++){
vis[i+k][j-k]=1;
if(i+k==8||j-k==0)
break;
}
dfs(k+1,i,j);
c[i][j]='.';
for(int o=1;o<=8;o++)
for(int p=1;p<=8;p++)
vis[o][p]=g[o][p];
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
for(int i=1;i<=8;i++)
for(int j=1;j<=8;j++)
cin>>c[i][j];
for(int i=1;i<=8;i++){
for(int j=1;j<=8;j++){
if(c[i][j]=='Q'){
for(int k=1;k<=8;k++){
if((c[i][k]=='Q'&&k!=j)||(c[k][j]=='Q'&&k!=i)){
cout<<"No Answer"<<endl;
return 0;
}
vis[i][k]=1;
vis[k][j]=1;
}
for(int k=1;k<=8;k++){
if(c[i-k][j-k]=='Q'){
cout<<"No Answer"<<endl;
return 0;
}
vis[i-k][j-k]=1;
if(i-k==0||j-k==0)
break;
}
for(int k=1;k<=8;k++){
if(c[i+k][j+k]=='Q'){
cout<<"No Answer"<<endl;
return 0;
}
vis[i+k][j+k]=1;
if(i+k==8||j+k==8)
break;
}
for(int k=1;k<=8;k++){
if(c[i-k][j+k]=='Q'){
cout<<"No Answer"<<endl;
return 0;
}
vis[i-k][j+k]=1;
if(i-k==0||j+k==8)
break;
}
for(int k=1;k<=8;k++){
if(c[i+k][j-k]=='Q'){
cout<<"No Answer"<<endl;
return 0;
}
vis[i+k][j-k]=1;
if(i+k==8||j-k==0)
break;
}
}
}
}
dfs(1,1,1);
cout<<"No Answer"<<endl;
return 0;
}
レースゲーム
题目传送门
题目大意
给定起点和终点,给出
思路
咕咕咕。
代码
咕咕咕。
贪心只能过样例
题目传送门
题目大意
有一个序列
思路
题目都提示过了,贪心只能过样例,所以这道题用 DP。
设
是这样的,但是复杂度估计得爆炸。
注意到
用 bitset
优化该解法。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
bitset<1000001>f[101];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
f[0][0]=1;
for(int i=1;i<=n;i++){
int l,r; cin>>l>>r;
for(int j=l;j<=r;j++){
f[i]|=(f[i-1]<<(j*j));
}
}
cout<<f[n].count()<<endl;
return 0;
}
[eJOI2020 Day1] Fountain
题目传送门
题目大意
咕咕咕。
思路
神仙题,把各大算法非常好地联系在了一起。
我们发现每一次往下流,只会流到第
但是这样一个一个跟着单调栈枚举下去最坏情况的复杂度为
发现对于
不难想到,对这个问题倍增肯定要预处理出所有
时间复杂度
(以下是闲话)
AC
完这道题之后可以去看看洛谷的题解,里面有一个是把这个题转化成树上倍增 LCA 的算法非常巧妙,建议去看看。
这是欧洲 OI 的题,洛谷上这道题评分为 绿
,但其实难度不小,我觉得难度应该有 蓝
。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,q;
int d[100005],c[100005];
stack<int>s;
int to[100005][55]={0};
int sum[100005][55]={0};
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>q;
for(int i=1;i<=n;i++)
cin>>d[i]>>c[i];
d[++n]=1e17; c[n]=1e17;
for(int i=1;i<=n;i++){
while(!s.empty()&&d[i]>d[s.top()]){
to[s.top()][0]=i;
sum[s.top()][0]=c[i];
s.pop();
}
s.push(i);
}
for(int j=1;j<=19;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
to[i][j]=to[to[i][j-1]][j-1];
sum[i][j]=sum[i][j-1]+sum[to[i][j-1]][j-1];
}
}
while(q--){
int r,v; cin>>r>>v;
if(v<=c[r]){
cout<<r<<endl;
continue;
}
v-=c[r];
for(int i=19;i>=0;i--){
if(to[r][i]!=0&&v>sum[r][i]){
v-=sum[r][i];
r=to[r][i];
}
}
cout<<(to[r][0]==n?0:to[r][0])<<endl;
}
return 0;
}
最大食物链计数
题目传送门
题目大意
给定一个有向无环图
也就是求图中一对
-
与 之间存在一条路径。 -
入度为 。 -
出度为 。
思路
很水的套板子题。求路径计数,很显然地使用 DP。
设
显然为了满足无后效性,我们需要把图拓扑排序。
这道题确实水了一些,但是可以作为图上 DP 的入门题,也是一道好题。
最坏时间复杂度为
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,in[100005]={0},out[100005]={0};
vector<int>V[100005];
vector<int>U[100005];
int f[100005]={0},tp[100005]={0},cnt=0;
const int MOD=80112002;
queue<int>q; int ans=0;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v; cin>>u>>v;
V[u].push_back(v);
U[v].push_back(u);
in[v]++; out[u]++;
}
for(int i=1;i<=n;i++){
if(!in[i]){
q.push(i);
f[i]=1;
}
}
while(!q.empty()){
int t=q.front();
q.pop(); tp[++cnt]=t;
for(int i=0;i<V[t].size();i++){
if(in[V[t][i]]){
in[V[t][i]]--;
if(!in[V[t][i]])
q.push(V[t][i]);
}
}
}
for(int i=1;i<=n;i++){
int p=tp[i];
for(int j=0;j<U[p].size();j++){
f[p]+=f[U[p][j]];
f[p]%=MOD;
}
}
for(int i=1;i<=n;i++){
if(out[i]==0){
ans=ans+f[i];
ans%=MOD;
}
}
cout<<ans<<endl;
return 0;
}
[USACO23JAN] Moo Route S
题目传送门
题目大意
有一个点在数轴上从原点移动了若干次后回到了原点。给出其经过的
思路
显然我们应该设一个标记方向的变量
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,a[100005]={0};
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i-1];
int pos=0,d=1,r=n+1;
while(1){
if(pos==0&&a[pos]==0){
break;
}
if(d==1){
if(a[pos]>0){
a[pos]--;
cout<<"R";
pos++;
}
else{
a[pos-1]--;
cout<<"L";
pos--; d=-1;
}
}
else{
if(a[pos-1]>1||a[pos]==0){
a[pos-1]--;
cout<<"L";
pos--;
}
else{
a[pos]--;
cout<<"R";
pos++; d=1;
}
}
}
return 0;
}
[ABC251D] At Most 3 (Contestant ver.)
题目传送门
[ABC251D] At Most 3 (Contestant ver.)
题目大意
给出
-
。 -
对于每一个
,都有在 中取出最多三个数的和等于 。
思路
显然,这道题和
考虑将一个
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int w; cin>>w;
cout<<99*3<<endl;
for(int i=1;i<=99;i++){
cout<<i*10000<<' ';
}
for(int i=1;i<=99;i++){
cout<<i*100<<' ';
}
for(int i=1;i<=99;i++){
cout<<i<<' ';
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现