#include<bits/stdc++.h>
using namespace std;
int a[101],ans;
bool vis[20240000];
bool check(int date)
{
if(vis[date]) return false;//如果该日期访问过,就不行
vis[date]=1;
int mm=date/100%100;//月份(因为date的最后两位是日期,把最后两个去掉,然后剩下的两个就是月份)
int dd=date%100;//日期
if(mm<1||12<mm) return false;//月份非法
if(mm==1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12){
if(1<=dd&&dd<=31) return true;
}else if(mm==2){//2023年的2月有28天
if(1<=dd&&dd<=28) return true;
}else if(1<=dd&&dd<=30) return true;
else return false;//都不满足
}
void dfs(int x,int pos,int date){//x表示遍历到哪个数字的下标,pos指这个长度为8的子序列遍历到哪个地方,date指形成这样的一个日期
if(x==100) return;//表示这个数组遍历完了,直接return
if(pos==8){
if(check(date)) ++ans;//check函数表示如果它是2023年中的合法日期并且没有重复,ans就++
return;
}
if((pos==0&&a[x]==2)||//如果子序列是第零位并且满足该位数字为2
(pos==1&&a[x]==0)||//如果子序列是第1位并且满足该位数字为0
(pos==2&&a[x]==2)||//如果子序列是第2位并且满足该位数字为2
(pos==3&&a[x]==3)||//如果子序列是第3位并且满足该位数字为3
(pos==4&&0<=a[x]&&a[x]<=1)||//表示月份的十位
(pos==5&&0<=a[x]&&a[x]<=9)||//表示月份个位
(pos==6&&0<=a[x]&&a[x]<=3)||//表示日期的十位
(pos==7&&0<=a[x]&&a[x]<=9))//表示日期的个位
dfs(x+1,pos+1,date*10+a[x]);
dfs(x+1,pos,date);//如果不满足上述情况,就不选
}
int main()
{
for(int i=0;i<100;i++) cin>>a[i];
dfs(0,0,0);
cout<<ans;
return 0;
}
答案:235
#include<bits/stdc++.h>
using namespace std;
typedef long double db;
const int N=23333333;//01串长度
const db ans=11625907.5798,eps=1e-4;//eps表示误差
int main()
{
for(int v=0;v<=N/2;v++){//0出现次数
int u=N-v;//1出现次数
db res=-1.0*u*u/N*log2(1.0*u/N)-1.0*v*v/N*log2(1.0*v/N);
if(fabs(res-ans)<eps){
cout<<v;
return 0;
}
}
return 0;
}
答案:11027421
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int n,a[N],b[N];
bool check_min(int v)
{
for(int i=1;i<=n;i++)
if(a[i]/v>b[i]) return false;
return true;
}
bool check_max(int v)
{
for(int i=1;i<=n;i++)
if(a[i]/v<b[i]) return false;
return true;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
int l=1,r=1e9,v_min;
while(l<=r){
int mid=l+r>>1;
if(check_min(mid)){
v_min=mid;
r=mid-1;
}else l=mid+1;
}
l=1,r=1e9;
int v_max;
while(l<=r){
int mid=l+r>>1;
if(check_max(mid)){
v_max=mid;
l=mid+1;
}else r=mid-1;
}
cout<<v_min<<' '<<v_max;
return 0;
}
/*#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int n;
int get(int a,int b){
int l=1,r=1e9+1;
while(l<r){
int mid=l+r>>1;
if(a/mid<=b) r=mid;
else l=mid+1;
}
}
int main()
{
cin>>n;
int v_min=1,v_max=1e9;
while(n--){
int a,b;
cin>>a>>b;
v_min=max(v_min,get(a,b));
v_max=min(v_max,get(a,b-1)-1);
}
cout<<v_min<<' '<<v_max;
return 0;
}*/
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int n;
int main()
{
cin>>n;
int v_min=1,v_max=1e9;
while(n--){
int a,b;
cin>>a>>b;
v_min=max(v_min,a/(b+1)+1);
v_max=min(v_max,a/b);
}
cout<<v_min<<' '<<v_max;
return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N=11;
int n,t[N],d[N],l[N];
bool have_answer,used[N];
void dfs(int x,int tim){
if(have_answer) return;
if(x==n){
have_answer=1;
return;
}
for(int i=1;i<=n;i++)
if(!used[i]&&tim<=t[i]+d[i]){
used[i]=1;
dfs(x+1,max(t[i],tim)+l[i]);
if(have_answer) return;
used[i]=0;
}
}
void solve(){
have_answer=0;
cin>>n;
for(int i=1;i<=n;i++) {
cin>>t[i]>>d[i]>>l[i];
used[i]=0;
}
dfs(0,0);
if(have_answer) cout<<"YES\n";
else cout<<"NO\n";
}
int main()
{
int t;
cin>>t;
while(t--) solve();
return 0;
}
//题目可以转化为求接龙子序列最长的长度,答案就是n-这个长度
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,dp[10];//dp存的是数位,只能是0~9,存储每个状态的最长接龙长度
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
int a;
cin>>a;
vector<int>d;
while(a){
d.push_back(a%10);
a/=10;
}
int y=*d.begin(),x=d.back();//y为最低位,x为最高位
dp[y]=max(dp[y],dp[x]+1);
}
int len=0;
for(int i=0;i<10;i++) len=max(len,dp[i]);
cout<<n-len;
return 0;
}
这段代码的思路是,将每个数字拆分成数位,然后将最低位和最高位作为状态,用 dp 数组存储每个状态的最长接龙长度。最后,遍历 dp 数组,找到最大值,用总数减去最大值即为最长接龙长度。
举个例子,假设输入为 123、234、345,那么拆分后的状态为:
1 -> 2 -> 3 2 -> 3 -> 4 3 -> 4 -> 5
dp 数组的初始值为 0,表示每个状态的最长接龙长度为 0。对于第一个状态 1 -> 2,最低位为 2,最高位为 1,因此 dp[2] = max(dp[2], dp[1] + 1) = 1,表示状态 2 -> 3 的最长接龙长度为 1。同理,对于状态 2 -> 3,dp[3] = max(dp[3], dp[2] + 1) = 1,表示状态 3 -> 4 的最长接龙长度为 1。对于状态 3 -> 4,dp[4] = max(dp[4], dp[3] + 1) = 1,表示状态 4 -> 5 的最长接龙长度为 1。最后,遍历 dp 数组,找到最大值为 1,因此最长接龙长度为 3 - 1 = 2
#include<bits/stdc++.h>
using namespace std;
const int N=51;
int t,m,n;
string mp[N];
bool vis[N][N],used[N][N];
int dx[]={0,0,1,-1,1,-1,1,-1};
int dy[]={1,-1,0,0,1,1,-1,-1};
void bfs_col(int x,int y){
queue<int>qx,qy;
qx.push(x);qy.push(y);vis[x][y]=1;
while(!qx.empty()){
x=qx.front();qx.pop();
y=qy.front();qy.pop();
for(int i=0;i<4;i++){
int nx=x+dx[i];
int ny=y+dy[i];
if(nx<0||m<=nx||ny<0||n<=ny||vis[nx][ny]||mp[nx][ny]=='0') continue;
qx.push(nx);qy.push(ny);vis[nx][ny]=1;
}
}
}
bool bfs_out(int x,int y){
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
used[i][j]=0;
queue<int>qx,qy;
qx.push(x);qy.push(y);used[x][y]=1;
while(!qx.empty()){
x=qx.front();qx.pop();
y=qy.front();qy.pop();
if(x==0||x==m-1||y==0||y==n-1) return true;
for(int i=0;i<8;i++){
int nx=x+dx[i];
int ny=y+dy[i];
if(nx<0||m<=nx||ny<0||n<=ny||used[nx][ny]||mp[nx][ny]=='1') continue;
qx.push(nx);qy.push(ny);used[nx][ny]=1;
}
}
return false;
}
void solve(){
cin>>m>>n;
for(int i=0;i<m;i++){
cin>>mp[i];
for(int j=0;j<n;j++)
vis[i][j]=0;
}
int ans=0;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
if(!vis[i][j]&&mp[i][j]=='1'){
bfs_col(i,j);
if(bfs_out(i,j)) ++ans;
}
cout<<ans<<'\n';
}
int main()
{
cin>>t;
while(t--) solve();
return 0;
}
使用 BFS 算法。具体实现如下:
-
首先输入矩阵的行数和列数,以及矩阵本身。
-
然后遍历整个矩阵,对于每个未被访问过的值为 1 的位置,进行 BFS 遍历。
-
在 BFS 遍历的过程中,记录已经访问过的位置,以及是否到达了矩阵的边界。
-
如果到达了矩阵的边界,则说明该连通块与矩阵的边界相连,将答案加 1。
-
最后输出答案。
代码中使用了两个 BFS 函数,分别用于遍历连通块和判断是否到达边界。其中,vis 数组用于记录是否访问过,used 数组用于记录 BFS 遍历过程中已经访问过的位置。
代码中的 dx 和 dy 数组表示了 BFS 遍历时的八个方向,分别为上、下、左、右、左上、右上、左下、右下。
代码中的 queue 表示队列,push 表示入队,front 表示队首元素,pop 表示出队。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int k;
string s;
char c1,c2;
int main()
{
cin>>k>>s>>c1>>c2;
int sum_c1=0;//c1的前缀和
int n=s.size();
LL ans=0;
for(int i=k-1,j=0;i<n;i++,j++){
if(s[j]==c1) sum_c1++;
if(s[i]==c2) ans+=sum_c1;
}
cout<<ans;
return 0;
}
代码的思路是,用双指针维护一个长度为 k 的滑动窗口,同时维护 c1 的前缀和,每次移动窗口时,如果窗口右端点为c2,则将当前的 sum_c1 加入答案中。
#include<bits/stdc++.h>
using namespace std;
#define val first
#define pos second
typedef long long LL;
typedef pair<LL,int>PLI;
const int N=5e5+5;
int n,k,pre[N],nxt[N];
LL a[N];
priority_queue<PLI>q;
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
pre[i]=i-1;
nxt[i]=i+1;
q.push({-a[i],-i});
}
pre[1]=-1;
nxt[n]=-1;
while(k--){
PLI now;
do{
now=q.top();q.pop();
now.val=-now.val;now.pos=-now.pos;
}while(a[now.pos]!=now.val);
int PRE=pre[now.pos];
int NXT=nxt[now.pos];
if(PRE!=-1){
a[PRE]+=now.val;
q.push({-a[PRE],-PRE});
nxt[PRE]=NXT;
}
if(NXT!=-1){
a[NXT]+=now.val;
q.push({-a[NXT],-NXT});
pre[NXT]=PRE;
}
a[now.pos]=-1;
}
for(int i=1;i<=n;i++)
if(a[i]!=-1)
cout<<a[i]<<" ";
return 0;
}
首先,将每个数看作一个叶子节点,将它们放入一个优先队列中。每次取出队列中最小的两个数,将它们合并成一个新的节点,并将这个新的节点放回队列中。这个新的节点的权值为两个原节点的权值之和。重复这个过程,直到队列中只剩下一个节点为止。这个节点就是哈夫曼树的根节点。
在这段代码中,我们不需要构造哈夫曼树,只需要用到哈夫曼编码的思想。我们将每个数看作一个叶子节点,并将它们放入一个优先队列中。每次取出队列中权值最小的数,将它与它相邻的两个数合并,并将合并后的数放回队列中。重复这个过程,直到合并了k次为止。最后,输出剩下的n-k个数。
这段代码的时间复杂度为O(nlogn),其中n为数组的长度。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+5;
vector<int>E[N],W[N];
int n,k,dep[N],fa[N][21],a[N];
LL dis[N];
void dfs(int u,int Fa){
dep[u]=dep[Fa]+1;
fa[u][0]=Fa;
for(int i=1;i<=20;i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=0;i<E[u].size();i++){
int v=E[u][i],w=W[u][i];
if(v==Fa) continue;
dis[v]=dis[u]+w;
dfs(v,u);
}
}
int LCA(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
for(int i=20;i>=0;i--)
if(dep[fa[u][i]]>=dep[v])
u=fa[u][i];
if(u==v) return u;
for(int i=20;i>=0;i--)
if(fa[u][i]!=fa[v][i]){
u=fa[u][i];
v=fa[v][i];
}
return fa[u][0];
}
LL path_dis(int u,int v){
if(!u||!v) return 0;
return dis[u]+dis[v]-2*dis[LCA(u,v)];
}
int main()
{
cin>>n>>k;
for(int i=1;i<n;i++){
int u,v,t;
cin>>u>>v>>t;
E[u].push_back(v);
W[u].push_back(t);
E[v].push_back(u);
W[v].push_back(t);
}
dfs(1,0);
LL ans=0;
for(int i=1;i<=k;i++)
{
cin>>a[i];
ans+=path_dis(a[i],a[i-1]);
}
for(int i=1;i<=k;i++)
cout<<ans-path_dis(a[i-1],a[i])-path_dis(a[i],a[i+1])+path_dis(a[i-1],a[i+1])<<" ";
return 0;
}
主要是通过预处理出每个节点到根节点的距离,然后通过LCA求出两个节点之间的距离,最后通过路径相减的方式求出多个节点之间的距离。
具体来说,代码中的dfs函数是用来预处理每个节点到根节点的距离的,其中dis数组表示每个节点到根节点的距离。LCA函数是用来求两个节点之间的距离的,其中fa数组表示每个节点的祖先节点,dep数组表示每个节点的深度。path_dis函数是用来求多个节点之间的距离的,其中a数组表示多个节点的编号。
首先读入n和k,然后通过循环读入n-1条边的信息,建立树的结构。接着调用dfs函数预处理每个节点到根节点的距离。然后通过循环读入k个节点的编号,计算多个节点之间的距离。最后通过循环输出每个节点之间的距离。
时间复杂度为O(nlogn)。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,dep[N],s[N],fa[N][21],ans;
vector<int>e[N],num[N];
void dfs(int u,int Fa){
dep[u]=dep[Fa]+1;
fa[u][0]=Fa;
for(int i=1;i<=20;++i)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(auto &v:e[u]){
if(v==Fa) continue;
dfs(v,u);
}
}
int LCA(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
for(int i=20;i>=0;--i)
if(dep[fa[u][i]]>=dep[v])
u=fa[u][i];
if(u==v) return u;
for(int i=20;i>=0;--i)
if(fa[u][i]!=fa[v][i]){
u=fa[u][i];
v=fa[v][i];
}
return fa[u][0];
}
void dfs2(int u,int Fa){
for(int i=0;i<e[u].size();++i){
int v=e[u][i],p=num[u][i];
if(v==Fa) continue;
dfs2(v,u);
s[u]+=s[v];
if(s[v]==m) ans=max(ans,p);
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<n;++i){
int x,y;
cin>>x>>y;
e[x].push_back(y);
num[x].push_back(i);
e[y].push_back(x);
num[y].push_back(i);
}
dfs(1,0);
for(int i=1;i<=m;++i){
int a,b;
cin>>a>>b;
s[a]++; s[b]++; s[LCA(a,b)]-=2;
}
dfs2(1,0);
cout<<ans;
return 0;
}
主要思路是先求出两点间的LCA,然后再从两点到LCA的路径上找到最大的边权。
代码中的dfs函数是用来求出每个节点的深度和其父节点的信息的。其中,fa[u][i]表示节点u的第2^i个祖先节点。
LCA函数是用来求两个节点的LCA的。首先将深度较大的节点u向上跳,直到与节点v的深度相等或更深。然后,同时向上跳,直到u和v的LCA。
dfs2函数是用来计算每个节点的子树中是否存在m个点的。如果存在,则更新ans的值。
最后,主函数中读入边的信息,计算每个节点的度数,然后调用dfs2函数求解答案。