haoi部分水题题解

bzoj 2423: [HAOI2010]最长公共子序列

直接dp就好了,要滚动不然M
code:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
const int mod=1e8;
struct node{
    int a,num;
    node() {a=num=0;}
    node(int x,int y) {a=x;num=y;}
}f[2][5010];int now=0;
node operator + (node a,node b) {return a.a==b.a?node(a.a,(a.num+b.num)%mod):(a.a>b.a?a:b);}
char s1[5010],s2[5010];
int n,m;
int main()
{
    scanf("%s %s",s1+1,s2+1);
    n=strlen(s1+1);m=strlen(s2+1);
    n--;m--;f[0][0].num=1;
    for(int i=1;i<=m;i++) f[0][i].num=1;
    for(int i=1;i<=n;i++)
    {
        now^=1;for(int j=0;j<=m;j++) f[now][j].a=f[now][j].num=0;
        f[now][0].num=1;
        for(int j=1;j<=m;j++)
        {
            if(s1[i]==s2[j])
            {
                node t=f[now^1][j-1];t.a++;
                f[now][j]=t;
            }
            f[now][j]=f[now][j]+(f[now^1][j]+f[now][j-1]);
            if(f[now^1][j-1].a==f[now][j].a) (f[now][j].num-=f[now^1][j-1].num)%=mod;
        }
    }
    if(f[now][m].a==0) f[now][m].num=1;
    printf("%d\n%d",f[now][m].a,(f[now][m].num+mod)%mod);
}

bzoj 2299: [HAOI2011]向量

假设最后的向量是 ( x a + y b , z a + w b ) (xa+yb,za+wb) (xa+yb,za+wb)
容易发现, x , w x,w x,w y , z y,z y,z的和都是2的倍数。
那么就直接爆搜+gcd判断就可以了。
code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
LL gcd(LL a,LL b) {return a==0?b:gcd(b%a,a);}
bool flag=false;
LL a,b,x,y,c[15];
void check()
{
    LL A=c[1]*a+c[2]*b,B=c[3]*b+c[4]*a;
    LL k1=x-A,k2=y-B;
    A=2*a;B=2*b;LL d=gcd(A,B);
    if(k1%d==0&&k2%d==0) flag=true;
}
void dfs(LL k)
{
    if(k>4) {check();return;}
    for(LL i=-1;i<=1;i++)
    {
        if(k>2&&(i+c[k-2])%2!=0) continue;
        c[k]=i;dfs(k+1);
        if(flag) return;
    }
}
int main()
{
    LL T;scanf("%lld",&T);
    while(T--)
    {
        scanf("%lld %lld %lld %lld",&a,&b,&x,&y);
        flag=false;dfs(1);
        if(flag) printf("Y\n");
        else printf("N\n");
    }
}

2749: [HAOI2012]外星人

容易发现所有数最终都被分解成2,所以答案就是最终分解出来的2的数量。
类似线性筛求出每一个数最终分解出多少个2即可。
假如是奇数答案+1。
code:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
LL prime[100010],pr=0,g[100010];
bool vis[100010];
void pre()
{
    memset(vis,true,sizeof(vis));g[1]=1;
    for(LL i=2;i<=100000;i++)
    {
        if(vis[i]) prime[++pr]=i,g[i]=g[i-1];
        for(LL j=1;j<=pr&&i*prime[j]<=100000;j++)
        {
            LL s=i*prime[j];vis[s]=false;g[s]=g[i]+g[prime[j]];
            if(i%prime[j]==0) break;
        }
    }
}
LL n;
int main()
{
    pre();
    LL T;scanf("%lld",&T);
    while(T--)
    {
        scanf("%lld",&n);
        LL ans=0;LL flag=1;
        for(LL i=1;i<=n;i++)
        {
            LL p,q;scanf("%lld %lld",&p,&q);
            flag&=(p&1);ans+=(LL)g[p]*q;
        }
        printf("%lld\n",ans+flag);
    }
}

bzoj 4037: [HAOI2015]数字串拆分

因为m很小,所以可以矩阵乘法求f。
先预处理出 g [ i ] [ j ] g[i][j] g[i][j],表示 i   j i~j i j这个数的最终矩阵是什么,这里是 O ( n 2 m 3 k ) O(n^2m^3k) O(n2m3k),k是一个常数。
然后因为矩阵满足分配率,就可以随便求一下最终的矩阵。
然而这个复杂度很假……然而好像这样就能过了……
貌似有 O ( n 2 m 2 ) O(n^2m^2) O(n2m2)的做法。

bzoj 4035: [HAOI2015]数组游戏

orz
code:

#include<map>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n,q;
map<int,int> f;
int calc(int x)
{
    if(f.count(x)) return f[x];
    bool vis[210];int ans=0;
    memset(vis,false,sizeof(vis));
    for(int i=2,j;i<=x;i=j+1)
    {
        j=x/(x/i);
        int tmp=calc(x/i);
        vis[ans]=vis[tmp^ans]=true;
        if((j-i+1)&1) ans^=tmp;
    }
    for(ans=1;ans;ans++) if(!vis[ans]) break;
    f[x]=ans;return ans;
}
int main()
{
    scanf("%d %d",&n,&q);
    while(q--)
    {
        int k,ans=0;scanf("%d",&k);
        while(k--)
        {
            int x;scanf("%d",&x);
            ans^=calc(n/x);
        }
        puts(ans?"Yes":"No");
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值