暑假集训 7月7日

dfs(尽可能往深搜)栈O(n)

顺序+剪枝

全排列

复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=10;
int path[N];
bool st[N];
int n;
void dfs(int u)
{
    if (u==n)
    {
        for (int i=0;i<n;i++)
        {
            cout<<path[i]<<' ';
        }
        cout<<"\n";//关闭同步流以后的注意事项
    }
    for (int i=1;i<=n;i++)
    {
        if (!st[i])
        {
            path[u]=i;
            st[i]=true;
            dfs(u+1);
            st[i]=false;
        }
    }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    dfs(0);
    return 0;
}
复制代码

 acwing 健康的荷斯坦奶牛

复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=30;
bool tog=1;
int a[N],val[N];
int v,g;
int num[N][N];
vector<int>path,ans;
bool check()
{
    memset(val,0,sizeof val);
    for (int i=0;i<v;i++)
    {
        for (int j=0;j<path.size();j++)
        {
            val[i]+=num[path[j]][i];
        }
        if (val[i]<a[i])return false;
    }
    if (ans.empty()||ans.size()>path.size()||(ans.size()==path.size()&&ans>path))
        return true;
    return false;
}
void dfs(int u)
{
    if (u>g)
    {
        if (check())ans=path;
        return;
    }
    //不选
    path.push_back(u);
    dfs(u+1);
    path.pop_back();
    //
    dfs(u+1);
}
signed main()
{
    cin>>v;
    for (int i=0; i<v; i++)cin>>a[i];
    cin>>g;
    for (int i=0; i<g; i++)
    {
        for (int j=0; j<v; j++)
        {
            cin>>num[i][j];
        }
    }
    dfs(0);
    int w=ans.size();
    cout<<w<<' ';
    for (int i=0; i<w; i++)
    {
        cout<<ans[i]+1<<' ';
    }
    puts("");
    return 0;
}
复制代码

 acwing 小猫爬

复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=30;
int n,w,ans=18;
int a[N],vol[N];
void dfs(int u,int num)
{
    if (num>=ans)return;
    if (u==n)
    {
        ans=num;
        return;
    }
    for (int i=0;i<num;i++)
    {
        if (vol[i]+a[u]<=w)
        {
            vol[i]+=a[u];
            dfs(u+1,num);
            vol[i]-=a[u];
        }
    }
    vol[num]=a[u];//再开一个车筐
    dfs(u+1,num+1);
    vol[num]=0;
}
signed main()
{
    cin>>n>>w;
    for (int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    sort(a,a+n);
    reverse(a,a+n);//从大到小排序
    dfs(0,0);
    cout<<ans<<"\n";
    return 0;
}
复制代码

 1<<9-1=111111111

1<<9=1000000000

再减1就是111111111(二进制)

acwing 数独(人没了)

 

复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=9,M=1<<N;
int ones[M],MAP[M];
int row[N],col[N],cell[3][3];
char str[100];
void init()
{
    for (int i=0; i<N; i++)
        row[i]=col[i]=(i<<N)-1;
    for (int i=0; i<3; i++)
        for (int j=0; j<3; j++)
            cell[i][j]=(1<<N)-1;
}
void draw(int x,int y,int t,bool is_set)
{
    if (is_set)str[x*N+y]='1'+t;
    else str[x*N+y]='.';
    int v=1<<t;
    if (!is_set)v=-v;
    row[x]-=v;
    col[y]-=v;
    cell[x/3][y/3]-=v;
}
int lowbit(int x)
{
    return x&-x;
}
int get(int x,int y)
{
    return row[x]&col[y]&cell[x/3][y/3];
}
bool dfs(int cnt)
{
    if (!cnt)return true;
    int mi=10;
    int x,y;
    for (int i=0; i<N; i++)
        for (int j=0; j<N; j++)
            if (str[i*N+j]=='.')
            {
                int st=get(i,j);
                if (ones[st]<mi)
                {
                    mi=ones[st];
                    x=i,y=j;
                }
            }
      int st=get(x,y);
      for (int i=st;i;i-=lowbit(i))
      {
          int t=MAP[lowbit(i)];
          draw(x,y,t,true);
          if (dfs(cnt-1))return true;
          draw(x,y,t,false);
      }
      return false;
}
signed main()
{
    for (int i=0; i<N; i++)MAP[1<<i]=i;
    for (int i=0; i<1<<N; i++)
        for (int j=0; j<N; j++)
            ones[i]+=i>>j&1;
    while (cin>>str,str[0]!='e')
    {
        init();
        int cnt=0;
        for (int i=0,k=0; i<N; i++)
            for (int j=0; j<N; j++,k++)
                if (str[k]!='.')
                {
                    int t=str[k]-'1';
                    draw(i,j,t,true);
                }
                else cnt++;
        dfs(cnt);
        puts(str);
    }
    return 0;
}
复制代码

 

bfs(一层一层搜)队列 O(2^n)最短性

 

dijkstra

 

floyd

 

二分图

 

补题:

B - Latin Squares

 凭什么呀,没说多组输入好吗。。。

复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=120;
string s[N];
int cnt[N][N];
int num[N][N];
signed main()
{
    int n,i,j,k;
    while (cin>>n)
    {
        memset(cnt,0,sizeof cnt);
        memset(num,0,sizeof num);
        bool f=1,ff=1;
        for (i=0; i<n; i++)
        {
            cin>>s[i];
        }
        for (i=0; i<n; i++)
        {
            for (j=0; j<n; j++)
            {
                if (s[i][j]>='A'&&s[i][j]<='Z')
                    s[i][j]=s[i][j]-'A'+10;
                else if (s[i][j]>='0'&&s[i][j]<='9')
                    s[i][j]-='0';
            }
        }
        for (i=1; i<n; i++)
        {
            if (s[i][0]==s[0][i]&&(int)(s[0][i]-s[0][i-1])==1)
            {
                continue;
            }
            else
            {
                ff=0;
                break;
            }
        }
        for (i=0; i<n; i++)
        {
            for (j=0; j<n; j++)
            {
                cnt[i][(int)s[i][j]]++;
            }
            for (k=0; k<=35; k++)
                if (cnt[i][k]>1)f=0;
        }
        for (j=0; j<n; j++)
        {
            for (i=0; i<n; i++)
            {
                num[j][(int)s[i][j]]++;
            }
            for (k=0; k<=35; k++)
                if (num[j][k]>1)f=0;
        }
        if (!f)puts("No");
        else if (f&&!ff)puts("Not Reduced");
        else if (f&&ff)puts("Reduced");
    }
    return 0;
}
复制代码

 

K - Star Arrangements

 简单水题,当时没看懂题意。。。

复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    int n;
    cin>>n;
    printf("%d:\n",n);
    int x=n/2;
    if (n%2)x+=1;
    int i,j;
    for (i=2;i<=x;i++)
    {
        for (j=i-1;j<=i;j++)
        {
            int a=i,b=j;
            if ((b==a-1)&&((n%(a+b)==a)||(n%(a+b)==0)))
                printf("%d,%d\n",a,b);
            else if (b==a)
            {
                if (n%a==0)printf("%d,%d\n",a,a);
            }
        }
    }
    return 0;
}
复制代码

 

H - Unloaded Die

 问的是改的概率差值最小是多少,所以用期望的差值除以最大的概率就行。(雀食)

复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=10;
double a[N];
int main()
{
    double ans=0;
    double ma=-0x3f3f3f3f;
    for (int i=1; i<=6; i++)
    {
        cin>>a[i];
        ma=max(ma,a[i]);
        ans+=i*a[i];
    }
    double res=abs(3.5-ans);
    printf("%.3lf\n",res/ma*1.0);
    return 0;
}
复制代码

C - Fear Factoring

题意:给a,b两个数,求a到b所有数的因数和。

题目分析:我们考虑依次枚举1-n中的每一个约数,比如在1-7中,2是2、4、6的约数,3是3、6的约数,4是4的约数,可以发现每一个约数x在1-7中出现的次数是7/x(向下取整),推广到一般情况,对于1-n中的约数x,它最多是n/x个 数 的因子,也就是说,我们要求S(题目描述中有),可以分别求出每一个约数(这里的约数就是1-n中的每一个数)出现的次数并和约数相乘在累加。
比如:
1-n:    1  2 3  4  5  6  7  8  9  10
次数:  10 5 3  2  2  1  1  1  1   1

如果暴力找的话,时间复杂度太高,所以就用到了除法分块,经过观察可以发现,有某个区间的约数,出现的次数是一样的,所以用除法分块将这个区间找到,然后根据数列性质求和。
所谓分块,就是把一段数分成不同的区间,而这些区间的每一个数除以同一个数的值是相同的,所以我们就把这些区间统一处理,就不用再来一个一个遍历

例: 问题中我们假设n = 10。那么我们现在分一下{1},{2},{3},{4,5},{6,7,8,9,10}。

我们知道初始l肯定是等于1,每次算到了r后,再把l更新到r + 1即可。那么关键是r怎么确定?
先一步一步解释: (n / l)代表的是值为(n / l)的一类数的评定标准,也是这个区间的每一个数对答案的增长的价值。
那么n / (n/l),就是代表这一类数的最大值(也就是右端点r)。

以下式子都可以用除法分块

 

 (除法分块)不会

复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ull unsigned long long
ull l,r;
ull num(ull n)
{
    ull sum=0;
    for(ull l=1,r;l<=n;l=r+1)
    {
        r=n/(n/l);//除法分块
        sum=sum+(n/l)*(r-l+1)*(l+r)/2;//等差数列求和
    }
   //(n/l)为该因子出现的次数,n/(n/l)为出现该因子次数的最大因子
    return sum;  
}
void solve()
{
    ull a,b;
    cin>>a>>b;
    cout<<num(b)-num(--a)<<"\n";
}
signed main()
{
    int t=1;
    //cin>>t;
    while (t--)
    {
        solve();
    }
    return 0;
}
复制代码

 

范围

 

F - Purple Rain(最大子段和)

复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int q[N];

signed main()
{
    string s;
    cin>>s;
    int len=s.size();
    if (len==1)puts("1 1");
    s="#"+s;
    for (int i=1;i<=len;i++){
        if (s[i]=='B')
            q[i]=q[i-1]+1;
        else 
            q[i]=q[i-1]-1;
    }
    int l=0,r=0;
    int ma=0,mi=0;
    for (int i=1;i<=len;i++){
        if (ma>q[i]){
            ma=q[i];
            l=i;
        }
        if (mi<q[i]){
            mi=q[i];
            r=i;
        }
    }
    cout<<min(l,r)+1<<' '<<max(l,r)<<"\n";
    return 0;
}
复制代码

 

posted @   好腻友Π  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示