• Codeforces Round #637


    Codeforces Round #637

    A.数学

    给定k,a,b,c,d

    问 区段 k * ( a - b ) 到 k * ( a + b ) 与 区段 c - d 到 c + d 是否有重合部分

    简单判断左右端即可

    B.前缀和

    形如131,1231的各一个山峰3,而1234无

    现在给定你一个串,你取其中长度为k的子串,使得它的山峰数越多,如果有多种可能取最左的选择

    比如1213,k=3,取前三个有一个山峰,后三个一个没有

    思路:

    前缀和

    首先处理一下哪些是山峰

    然后前缀和记录山峰个数,注意当前山峰位置记录的个数不能加1,因为它若作端不算山峰,应该考虑,区段内的山峰数,即下一位才加1

    同样减去前缀的时候也要注意是额外要加1处理

    AC:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define maxn 200005
    #define minn -105
    #define ll long long int
    #define ull unsigned long long int
    ll a[maxn],pre[maxn];
    ll max(ll a,ll b)
    {
        return a>b?a:b;
    }
    void solve()
    {	
    	int n,k;
    	cin>>n>>k;
    	ll curmax=0;
    	memset(pre,0,sizeof(pre));
    	for(int i=0;i<n;i++)
    	{	
        	cin>>a[i];
        	pre[i]+=pre[i-1];
        	if(i>=2&&a[i-2]<a[i-1]&&a[i-1]>a[i])pre[i]++;
        	if(i>=k-1)curmax=max(curmax,pre[i]-pre[i-k+2]);
    	}
    	for(int i=k-1;i<n;i++)
        {
            if(pre[i]-pre[i-k+2]==curmax)
            {
                cout<<curmax+1<<" "<<i+2-k<<endl;
                return;
            }
        }
    }
    int main()
    {
        int t;
        cin>>t;
        for(int i=0;i<t;i++)
            solve();
        return 0;
    }
    

    C.找规律

    原题地址:https://codeforces.ml/contest/1341/problem/C

    这题题意很复杂,读懂其实不难,这里懒得翻译

    思路:

    一开始r数组为12345...k(k+1)...n

    你放1,除了最右端的位置,其他位置k你只要一放,

    队列就成了 12345...(k+1)(k+1)...n

    那么你的2就只能放k+1了,故2若出现在1右侧则1必须与2相邻

    同理3也是...

    那么就可以形成形如这样的队列:

    895671234

    如果队列不长这样那么就不行

    怎么判别?

    思路一:从1开始往右扫,直到触界,1234,取5对应的位置,567,取8的位置,89

    思路二:利用性质——只要比当前元素大1的在当前元素的右边,那么他们必定相邻

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define maxn 100005
    #define minn -105
    #define ll long long int
    #define ull unsigned long long int
    #define uint unsigned int
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'||ch>'9')last=ch,ch=getchar();
        while(ch>='0'&&ch<='9')ans=ans*10+ch-'0',ch=getchar();
        if(last=='-')ans=-ans;
        return ans;
    }
    int a[maxn],pos[maxn];
    void solve()
    {
        int n=read();
        int cur=0;
        bool ok=1;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            pos[a[i]]=i;
        }
        for(int i=1;i<n;i++)
        {
            if(pos[i]<pos[i+1]&&pos[i+1]-pos[i]!=1)ok=0;
        }
        if(ok)cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    	}
    int main()
    {
        int _t;
        _t=read();
        while(_t--)solve();
        return 0;
    }
    

    D.DP

    原题链接:https://codeforces.ml/contest/1341/problem/D

    题意,给你n个数用火柴棒表示,现在给你额外k个火柴棒,你添上去使得新数最大

    每个位置火柴棒的有无均采用01,最先给出的是最高位,注意k,n<=2000

    思路:动态规划

    首先注意到这个范围才2000,比较小

    其次我们想如果对于55,我们只有一根火柴,那么肯定优先添加给高位成为95

    所以我们DP要从低位开始,我们数组dp[第几个数][到现在一共用了几根],用它表示第几个数在使用了一共几根下对应的最大数字

    状态转移方程

    if(dp[i-1][j-k]有解)dp[i][j]=opt{save[i][k],0<=k<=min(7,j)}

    当dp[i-1][j-k]存在值,即低位均有可行解时,我们掏了k根给第i号数,而save[i][k],指的是当第i号数它接受了k个火柴最优值的情况,把这个值给了dp

    所以我们要先预处理save[i][k]:枚举每个数i(0->n-1),枚举数字(0->9)(如果你枚举给他k个火柴的话会很麻烦),与0-9每一位进行对比,记录可添加火柴数的情况(非法情况记为-1)

    DP过程:注意结果要求输出,所以还要记录你具体给每个数多少根,只要每个dp[i][j]对应记录一个pre[i][j],表示当前方案下第i号数取给了多少根,得到dp[i-1][m]后往回找、输出即可

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define maxn 2005
    #define minn -105
    #define ll long long int
    #define ull unsigned long long int
    const string num[10]= {"1110111", "0010010", "1011101", "1011011", "0111010",
                        "1101011", "1101111", "1010010", "1111111", "1111011"};
    int n,m;
    int dp[maxn][maxn],pre[maxn][maxn],save[maxn][8];
    string s[maxn];
    void init()
    {	
    	for(int i=0;i<n;i++)
    	    for(int j=0;j<8;j++)
    	        save[i][j]=-1;
    	for(int i=0;i<n;i++)
    	    for(int j=0;j<=m;j++)
    	        dp[i][j]=pre[i][j]=-1;
    }
    void deal()
    {
        for(int i=0;i<n;i++)
            for(int j=0;j<10;j++)
            {
                bool ok=1;
                int cnt=0;
                for(int bit=0;bit<7;bit++)
         	   {
                    if(s[i][bit]=='1'&&num[j][bit]=='0')
                    {
                        ok=0;
                        break;
                    }
                    if(s[i][bit]=='0'&&num[j][bit]=='1')
                        cnt++;
                }
                if(ok)save[i][cnt]=max(save[i][cnt],j);
            }
    }
    void DP()
    {
        for(int i=0;i<=min(7,m);i++)
        {
            dp[0][i]=save[0][i];
            pre[0][i]=i;
        }
        for(int i=1;i<n;i++)
            for(int j=0;j<=min(m,(i+1)*7);j++)
                for(int k=0;k<=min(j,7);k++)
                {
                    if(save[i][k]==-1||dp[i-1][j-k]==-1)continue;
                    if(save[i][k]>dp[i][j])
                    {
                        dp[i][j]=save[i][k];
                    	pre[i][j]=k;
                    }
                }
        if(dp[n-1][m]==-1)
        {
            cout<<-1<<endl;
            return;
        }
        for(int i=n-1;i>=0;i--)
        {
            cout<<dp[i][m];
            m-=pre[i][m];
        }
        cout<<endl;
    }
    int main()
    {
        cin>>n>>m;
        for(int i=0;i<n;i++)
            cin>>s[i];
        reverse(s,s+n);
        init();
        deal();
        DP();
        return 0;
    }
  • 相关阅读:
    第四周:卷积神经网络 part3
    第四周作业:卷积神经网络学习part3
    视频学习--《 图像语义分割前沿进展》
    视频学习--《语义分割中的自注意力机制和低秩重建》
    第二次作业:卷积神经网络 part 1
    使用VGG模型迁移学习进行猫狗大战
    使用 VGG16 对 CIFAR10 分类
    CIFAR10 数据集分类
    MNIST数据集分类
    第一次作业:深度学习基础
  • 原文地址:https://www.cnblogs.com/et3-tsy/p/12768601.html
Copyright © 2020-2023  润新知