20221009

20221009(种)

题目

小朋友的数字

题意

每个人有3个数值,手上的数字,特征值和分数。

  • 每个人的特征值是这个人之前(包括这个人)的最大连续子段和。
  • 每个人的分数是这个人之前(不包括这个人)的所有人中分数与特征值和的最大值。

思路

​ 我们要求最大分数,而求分数就要求特征值,而特征值就是求最大连续子段和,求最大连续子段和一个\(dp\)就可以完成,\(dp[i]\)表示到第\(i\)个数的最大连续子段和,\(kp[i]\)表示从\(i\)\(i\)之前的数的最大连续子段和则有:

\[kp[i]=max(kp[i-1]+a[i],a[i])\\dp[i]=max(dp[i-1],kp[i]) \]

然后求分数时,只需维护一个最大值即可。

计算过程中可能会爆\(long long\),大致有三种处理方法。

  1. __int128
  2. 开一个\(long long\)类型的二维数组,第一维存一部分数字,第二维存一部分数字,最后求答案时把两个部分拼起来即可。
  3. 对答案取模,取模时保存一个模数和一个除数,求答案时复原即可。
点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define ll __int128
#define fo(i,x,y) for(int i=x;i<=y;++i)
using namespace std;
template<typename T>inline void in(T &x){
    x=0;int f=0;char c=getchar();
    for(;!isdigit(c);c=getchar())f|=(c=='-');
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
    x=f?-x:x;
}
template<typename T>inline void out(T x){
    if(x<0)x=~x+1,putchar('-');
    if(x>9)out(x/10);
    putchar(x%10^48);
}
const int N=1e6+5;
int n,p;
ll a[N];
ll kp[N],sc[N],b[N];
ll ans,eans;
bool f;
inline ll maX(ll a,ll b){ 
    return a>b?a:b;
}
inline ll abS(ll a){
    return a<0?-a:a;
}
signed main(){
    in(n),in(p);
    eans=ans=-1e18;
    ll sum=-1e18;
    fo(i,1,n){
        in(a[i]);
        kp[i]=i==1?a[i]:maX(kp[i-1]+a[i],a[i]);
        sum=maX(sum,kp[i]);
        b[i]=sum;
    }
    sc[1]=b[1];
    eans=sc[1];
    ans=sc[1]+b[1];
    for(int i=2;i<=n;++i){
        if(b[i-1]+sc[i-1]>ans)ans=b[i-1]+sc[i-1];
        sc[i]=ans;
        eans=maX(eans,ans);
    }
    eans<0?f=1:f=0;
    out(f?-abS(eans)%p:eans%p);
    return 0;
}

涂满它!

IDA*

以剩余颜色数作为估价函数进行IDA*即可。
点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,x,y) for(int i=x;i<=y;++i)
#define ll long long
using namespace std;
template<typename T>inline void in(T &x){
    x=0;int f=0;char c=getchar();
    for(;!isdigit(c);c=getchar())f|=(c=='-');
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
    x=f?-x:x;
}
template<typename T>inline void out(T x){
    if(x<0)x=~x+1,putchar('-');
    if(x>9)out(x/10);
    putchar(x%10^48);
}
const int N=9;
int n,map[N][N],color[6];
int fx[4]={0,1,0,-1},fy[4]={1,0,-1,0};
int v[N][N],limit;
inline bool check(int x,int y){
    if(x<=0||y<=0||x>n||y>n||v[x][y]==1)return 0;
    return 1;
}
int gu(){
    int temp=0;
    memset(color,0,sizeof(color));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(!color[map[i][j]]&&v[i][j]!=1){
                color[map[i][j]]=1;
                temp++;
            }
        }	
    }
    return temp;
}
void dfs(int now,int x,int y){
    v[x][y]=1;
    fo(i,0,3){
	int X=x+fx[i];
	int Y=y+fy[i];
	if(!check(X,Y))continue;
	v[X][Y]=2;
	if(map[X][Y]==now)dfs(now,X,Y);
    }
}
int paint(int now){
    int p=0;
    fo(i,1,n){
	fo(j,1,n){
	    if(map[i][j]==now&&v[i][j]==2)
		dfs(now,i,j),++p;
	}
    }
    return p;
}
bool IDA(int ci){
    int f=gu();
    if(ci+f>limit)return 0;
    if(!f)return 1;
    int tmp[N][N];
    fo(i,0,5){
	memcpy(tmp,v,sizeof(v));
	if(paint(i)&&IDA(ci+1))return 1;
	memcpy(v,tmp,sizeof(v));
    }
    return 0;
}
int main(){
    while(scanf("%d",&n)&&n){
	fo(i,1,n)fo(j,1,n)in(map[i][j]);
	memset(v,0,sizeof(v));
	dfs(map[1][1],1,1);
	for(limit=0;;++limit){
	    if(IDA(0)){
		out(limit),putchar('\n');
		break;
	    }
	}
    }
    return 0;
}

薇薇位位运算

这里推一手某位名大佬的博客:oWXDo

题目分析

​ 对于一堆数,我们每次可以进行两种运算&|,即按位与和按位或。对于任意两个数\(a,b\),我们可以让其中一个数变为\(a\)&\(b\),让另外一个数变为\(a\)|\(b\)。我们对它们计算的过程并不会改变他们二进制下\(1\)的总数,而只是把他们二进制下的\(1\)相互交换的过程。这样子操作怎么最大化所有数的平方和呢?其实非常简单。对于\(a^{2}+b^{2}\le(a+b)^{2}\),并且这里的\(a,b\ge0\),必然成立。所以我们只需要构造出尽可能让二进制下的\(1\)的个数最多的数即可。

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define fo(i,x,y) for(int i=x;i<=y;++i)
using namespace std;
template<typename T>inline void in(T &x){
    x=0;int f=0;char c=getchar();
    for(;!isdigit(c);c=getchar())f|=(c=='-');
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
    x=f?-x:x;
}
template<typename T>inline void out(T x){
    if(x<0)x=~x+1,putchar('-');
    if(x>9)out(x/10);
    putchar(x%10^48);
}
const int N=1e5+5;
int n,a[N];
int maxlen;
int t[N];
inline void turn(int x){
    int l=0;
    for(;x;x>>=1,++l)
	if(x&1)++t[l];
    return;
}
ll ans;
int tmp;
int main(){
    in(n);
    fo(i,1,n){
	in(a[i]);
	turn(a[i]);
    }
    fo(i,0,21)maxlen=max(maxlen,t[i]);
    for(int i=maxlen;i>=1;--i){
	ll sum=0;
	for(int j=21;j>=0;--j){
	    if(t[j]){
		--t[j];
		sum+=1<<j;
	    }
	}
	ans+=sum*sum;
    }
    out(ans);
    return 0;
}

开车旅行

预处理骗分

posted @ 2022-10-09 20:11  リン・グァン  阅读(19)  评论(1编辑  收藏  举报