zoukankan      html  css  js  c++  java
  • test20190815

    闲话

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

    题面

    题面

    T1

    Solution

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

    ((a-b)^3=(a-b) imes(a^2+a imes b+b^2))

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

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

    时间复杂度(O(N imes 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
    ");
    		else printf("NO
    ");
    	}
    	return 0;
    }
    

    T2

    Solution

    (70pts)做法:

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

    很显然(O(N^2 imes 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 imes(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
    ", ans);
    	return 0;
    }
    

    总结

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

    还是要好好加油啊。

  • 相关阅读:
    JavaScript得到当前窗口的所有大小值
    JavaScript 变量、作用域和内存问题
    jQuery html5Validate基于HTML5表单验证插件
    新世界
    2001年的火花
    High Dynamic Range Compression on Programmable Graphics Hardware
    运筹帷幄
    你还要在学校找什么东西?
    图行天下
    Supra Team
  • 原文地址:https://www.cnblogs.com/TheShadow/p/11360850.html
Copyright © 2011-2022 走看看