ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

test20190815

2019-08-15 22:00:35  阅读:202  来源: 互联网

标签:return bas int ll define test20190815 mod


闲话

这两天考试真是妙啊,打暴力都有200分qwq。

题面

题面

T1

Solution

因为是求立方之差,可以考虑立方差公式。

\((a-b)^3=(a-b)\times(a^2+a\times b+b^2)\)

又因为\(P\)是一个质数,所以\((a-b)\)和\((a^2+a\times b+b^2)\)里面一定有一个是1。明显,\((a^2+a\times b+b^2)\)一定大于1,所以可得到\((a-b)\)的值为1,也就是说,\(P\)一定是相邻两个数的立方差。

我们可以循环找一下,可以发现,当\(k=577351\)时,\(k^3-(k-1)^3\)的值第一次大于\(10^{12}\)。所以直接从1开始,一直枚举到找到答案或者差值大于\(P\)结束即可。

时间复杂度\(O(N\times MAXK)\)

Code

#include<bits/stdc++.h>
#define del(a,i) memset(a,i,sizeof(a))
#define ll long long
#define inl inline
#define il inl void
#define it inl int
#define ill inl ll
#define re register
#define ri re int
#define rl re ll
#define mid ((l+r)>>1)
#define lowbit(x) (x&(-x))
#define INF 0x3f3f3f3f
using namespace std;
template<class T>il read(T &x){
    int f=1;char k=getchar();x=0;
    for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;
    for(;k>='0'&&k<='9';k=getchar()) x=(x<<3)+(x<<1)+k-'0';
    x*=f;
}
template<class T>il print(T x){
    if(x/10) print(x/10);
    putchar(x%10+'0');
}
ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;}
it qpow(int x,int m,int mod){
    int res=1,bas=x%mod;
    while(m){
        if(m&1) res=(res*bas)%mod;
        bas=(bas*bas)%mod,m>>=1;
    }
    return res%mod;
}
const int MAXN = 577351,maxn = 578;
ll T,p;
bool check(ll p){
    for(ri i=1;i<=MAXN;++i){
        rl mns=1ll*i*i*i-1ll*(i-1)*(i-1)*(i-1);
        if(mns==p)
            return true;
        else if(mns>p) return false;
    }
    return false;
}
int main()
{
    freopen("cubicp.in","r",stdin);
    freopen("cubicp.out","w",stdout);
    read(T);
    while(T--){
        read(p);
        if(check(p)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

T2

Solution

\(70pts\)做法:

对于\(60\)%的数据,\(N<=1000,k<=20\)。

很显然\(O(N^2\times k)\)的算法是可以跑过的。

考虑DP题目名称不就是吗

我们定义\(DP_{i,j}\)表示到达第 \(i\) 个数,分成 \(j\) 段所得到的最小值。

方程转移也很简单。

\(DP_{i,j}=Min(DP_{s,j-1}+val_{s+1,i})\)

我们只用预处理出\(val_{i,j}\)就可以进行直接转移。

我们再看数据范围,在每一档里面都有一个点,所有的\(a_i\)完全相同。

我们简单分析一下,可以发现,当我们有 \(k\) 个相同值时,\(k\) 越大,它的贡献和 \(k-1\) 相差就越大,所以我们要将这 \(N\) 个数尽可能的均分为 \(k\) 份。

如果 \(N\) 能被 \(k\) 整除,那么每一段的大小都是 \(N/k\) ;如果不能整除,那么多出来的 \(rest\) 个数,将它们平分到 \(rest\) 个区间中。

每一段区间对答案的贡献很好计算,\(val=\frac{size\times(size-1)}{2}\)

然后直接乘上个数就是答案。

Code

#include<bits/stdc++.h>
#define del(a,i) memset(a,i,sizeof(a))
#define ll long long
#define inl inline
#define il inl void
#define it inl int
#define ill inl ll
#define re register
#define ri re int
#define rl re ll
#define mid ((l+r)>>1)
#define lowbit(x) (x&(-x))
#define INF 0x3f3f3f3f
using namespace std;
template<class T>il read(T &x){
    int f=1;char k=getchar();x=0;
    for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;
    for(;k>='0'&&k<='9';k=getchar()) x=(x<<3)+(x<<1)+k-'0';
    x*=f;
}
template<class T>il print(T x){
    if(x/10) print(x/10);
    putchar(x%10+'0');
}
ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;}
it qpow(int x,int m,int mod){
    int res=1,bas=x%mod;
    while(m){
        if(m&1) res=(res*bas)%mod;
        bas=(bas*bas)%mod,m>>=1;
    }
    return res%mod;
}
const int MAXN = 1e3+1;
int n,k,a[MAXN],val[MAXN][MAXN],w,dp[21][MAXN],cnt[MAXN][MAXN],last[MAXN];
int main()
{
    freopen("dp.in","r",stdin);
    freopen("dp.out","w",stdout);
    read(n),read(k),del(dp,0x3f);
    if(n<=1000){
        for(ri i=1;i<=n;++i) read(a[i]);
        for(ri i=1;i<=n;++i){
            val[1][i]=val[1][i-1]+cnt[a[i]][last[a[i]]];
            cnt[a[i]][i]=cnt[a[i]][last[a[i]]]+1,last[a[i]]=i;
        }
        for(ri i=2;i<=n;++i){
            ri mns=0;
            for(ri j=i;j<=n;++j){
                if(a[j]==a[i-1]) mns++;
                val[i][j]=val[i-1][j]-mns;
            }
        }
        dp[0][0]=0;
        for(ri s=1;s<=k;++s)
            for(ri i=1;i<=n;++i)
                for(ri j=0;j<i;++j)
                    dp[s][i]=min(dp[s][i],dp[s-1][j]+val[j+1][i]);
        printf("%d",dp[k][n]);
    }
    
    else{
        for(ri i=1;i<=n;++i) read(w);
        ri add=n%k,len=n/k;
        printf("%d",(k-add)*len*(len-1)/2+add*(len+1)*len/2);
    }
    return 0;
}

\(100\)pts做法:

令 \(DP_{i,j}\) 表示前 \(i\) 个数分成 \(j\) 段的最少价值。枚举这个断点 \(k\) ,有 \(DP_{i,j}\) = \(Min(DP_{k,j-1}+sum_{k+1,i})\) 。事实上这个 \(k\) 具有单调性,用经典的1D1D动态规划优化即可。什么东西啊(雾

Code

#include<iostream>
#include<cstdio>
using namespace std;
const int N=100010;
typedef long long LL;
int c[N],a[N];
LL f[N],g[N];
int p,q,n,k;
LL tot;
void move(int l,int r)
{
    while (l<p) p--,tot+=c[a[p]],c[a[p]]++;
    while (r>q) q++,tot+=c[a[q]],c[a[q]]++;
    while (p<l) c[a[p]]--,tot-=c[a[p]],p++;
    while (r<q) c[a[q]]--,tot-=c[a[q]],q--;
}
void work(int l,int r,int fl,int fr)
{
    if (fl>fr) return;
    int mid=(fl+fr)>>1,mi;
    LL mx=1LL<<60;
    for (int i=l;i<=r;i++)
    if (i<mid)
    {
        move(i+1,mid);
        if (f[i]+tot<mx) mx=f[i]+tot,mi=i;
    }
    g[mid]=mx;
    work(l,mi,fl,mid-1);
    work(mi,r,mid+1,fr);
}
int main()
{
    freopen("dp.in","r",stdin);
    freopen("dp.out","w",stdout);
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    f[0]=0;
    for (int i=1;i<=n;i++) f[i]=1LL<<60;
    while (k--)
    {
        p=1,q=0,tot=0;
        for (int i=1;i<=n;i++) c[i]=0;
        work(0,n-1,1,n);
        for (int i=0;i<=n;i++) f[i]=g[i],g[i]=0;
    }
    cout<<f[n];
    return 0;
}

T3

Solution

对于所有区间最小值为x的操作的区间交只有一种情况会出现矛盾:对于最小值超过x的区间的并包含该区间交。

因此我们可以二分答案,之后将所有最小值从大到小进行排序,利用并查集维护即可。没看懂。。。

Code

#include <cstdio>
#include <iostream>
#include <algorithm>
#define N 1000011
#define min(x, y) ((x) < (y) ? (x) : (y))
#define max(x, y) ((x) > (y) ? (x) : (y))
using namespace std;
int n, q, ans;
int f[N];

struct node
{
    int x, y, z;
}p[N], t[N];

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    return x * f;
}

inline bool cmp(node x, node y)
{
    return x.z > y.z;
}

inline int find(int x)
{
    return x == f[x] ? x : f[x] = find(f[x]);
}

inline bool check(int k)
{
    int i, j, x, y, lmin, lmax, rmin, rmax;
    for(i = 1; i <= n + 1; i++) f[i] = i;
    for(i = 1; i <= k; i++) t[i] = p[i];
    std::sort(t + 1, t + k + 1, cmp);
    lmin = lmax = t[1].x;
    rmin = rmax = t[1].y;
    for(i = 2; i <= k; i++)
    {
        if(t[i].z < t[i - 1].z)
        {
            if(find(lmax) > rmin) return 1;
            for(j = find(lmin); j <= rmax; j++)
                f[find(j)] = find(rmax + 1);
            lmin = lmax = t[i].x;
            rmin = rmax = t[i].y;
        }
        else
        {
            lmin = min(lmin, t[i].x);
            lmax = max(lmax, t[i].x);
            rmin = min(rmin, t[i].y);
            rmax = max(rmax, t[i].y);
            if(lmax > rmin) return 1;
        }
    }
//  cout<<find(1)<<endl;
    if(find(lmax) > rmin) return 1;
    return 0;
}

int main()
{
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    int i, x, y, mid;
    n = read();
    q = read();
    for(i = 1; i <= q; i++)
        p[i].x = read(), p[i].y = read(), p[i].z = read();
    x = 1, y = q;
    //cout<<check(2)<<endl;
    //return 0;
    while(x <= y)
    {
        mid = (x + y) >> 1;
        if(check(mid)) ans = mid, y = mid - 1;
        else x = mid + 1;
    }
    printf("%d\n", ans);
    return 0;
}

总结

考完后进行交流大佬讲题的时候,发现自己还是好弱啊,说的东西都没听懂。。。

还是要好好加油啊。

标签:return,bas,int,ll,define,test20190815,mod
来源: https://www.cnblogs.com/TheShadow/p/11360850.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有