10.16

果然还是太菜了
T1想了很久,结果竟然是以前CYY讲的Meet in middle???
结果自己现在写的HASH又长又丑(还不如以前写的爆搜)
正解就是左右各分10个状态
暴力处理出左右的状态
最后再把左右状态合并

#include<bits/stdc++.h>
using namespace std;
int n,a[30],tot1,tot2,ans,tail=1,head=1;bool vis[1100000];
struct ss{int s,now;}x[1100000],y[1100000];
bool cmp1(ss x,ss y){return x.s<y.s;}bool cmp2(ss x,ss y){return x.s>y.s;}
void dfs(int l,int r,int s,int now)
{
    if(l>r)
    {
        if(r==n/2)x[++tot1].s=s,x[tot1].now=now;
        else y[++tot2].s=s,y[tot2].now=now;
        return;
    }dfs(l+1,r,s,now);
    dfs(l+1,r,s-a[l],now+(1<<(l-1)));
    dfs(l+1,r,s+a[l],now+(1<<(l-1)));
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    dfs(1,n/2,0,0);dfs(n/2+1,n,0,0);
    sort(x,x+tot1+1,cmp1);sort(y,y+tot2+1,cmp2);
    while(head<=tot1&&tail<=tot2)
    {
        while(y[tail].s>-x[head].s&&tail<=tot2)tail++;
        int pps=tail;
        while(tail<=tot2&&y[tail].s==-x[head].s)
        {
            if(!vis[x[head].now|y[tail].now])
                vis[x[head].now|y[tail].now]=1,ans++;
            tail++;
        }
        if(x[head].s==x[head+1].s&&head<tot1)tail=pps;
        head++;
    }printf("%d",ans-1);
}   

T2是一个大dp
f[i][j]表示前i个数,第i个数在前i个数中是第j小的
两种情况,q中i在i+1之前或是之后
\(\sum_{i=1}^{n} \sum_{j=1}^{n}f[i][j]=g[i-1][j-1]\)
\(\sum_{i=1}^{n} \sum_{j=1}^{n}f[i][j]=g[i-1][i]-g[i-1][j-1]\)
(g数组为前缀和优化)

#include<bits/stdc++.h>
using namespace std;
int f[5010][5010],g[5010][5010],n,ok[5010],ans,mo=1e9+7;vector<int> p;
int work()
{
	n=p.size();memset(ok,-1,sizeof(ok));
	for(int i=0;i<=n-1;i++)
	{
		if (p[i]>i)
		{
			if (i-1>=0){if (ok[i-1]==0) return 0;ok[i-1]=1;}
			for(int j=i;i<=p[i]-2;j++){if (ok[j]==1) return 0;ok[j]=0;}
			if (p[i]-1<=n-3){if (ok[p[i]-1]==0) return 0;ok[p[i]-1]=1;}
		}
		else if (p[i]<i)
		{
			if (p[i]-1>=0){if (ok[p[i]-1]==1) return 0;ok[p[i]-1]=0;}
			for(int j=p[i];j<=i-2;j++){if (ok[j]==0) return 0;ok[j]=1;}
			if (i-1<=n-3){if (ok[i-1]==1) return 0;ok[i-1]=0;}
		}else return 0;
	}f[0][1]=1;g[0][1]=1;
	for(int i=1;i<=n-2;i++)
		for(int j=1;j<=i+1;j++)
		{
			if (ok[i-1]!=1){(f[i][j]+=g[i-1][j-1])%=mo;}
			if (ok[i-1]!=0){(f[i][j]+=(g[i-1][i]-g[i-1][j-1])%mo)%=mo;}
			g[i][j]=(g[i][j-1]+f[i][j])%mo;
		}ans=0;for(int i=1;i<=n-1;i++)(ans+=f[n-2][i])%=mo;
	ans=(ans%mo+mo)%mo;return ans;
}
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++){int x;scanf("%d",&x);p.push_back(x);}printf("%d",work());}

T3智商检测题
就是在暴力的基础上,加上随机化
随机出+x的顺序,之后二分验证
若比之前二分结果更优,则check答案

#include<bits/stdc++.h>
using namespace std;
int n,p,K,a[10010],b[10010],w[10010],T[10010],ans;long long sum;bool ok[10010];
bool cmp(int x,int y){return x>y;}
bool check(int x)
{
	int res=0,pps=1;
	for(int i=1;i<=n;i++)
	{if(x<b[i])return 0;res+=b[i];if(res>x)pps++,res=b[i];}
	return pps<=K;
}
int main()
{
	srand('A'+'K'+'M'+'e'+'r');
	scanf("%d%d%d",&n,&p,&K);for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum+=a[i];ans=1e9;
	for(int i=0;i<p;i++){T[i]=rand()%p;while(ok[T[i]])T[i]=rand()%p;ok[T[i]]=true;}
	for(int i=0;i<p;i++)
	{
		for(int j=1;j<=n;j++)b[j]=(a[j]+T[i])%p;int l=0,r=sum;
		if(!check(ans))continue;
		while(l<=r)
		{
			int mid=(l+r)/2;
			if(check(mid))ans=min(ans,mid),r=mid-1;else l=mid+1;
		}
	}printf("%d",ans);
}
posted @ 2018-10-16 16:58  qwaszxxyf  阅读(135)  评论(0编辑  收藏  举报