1. 程式人生 > >haoi部分水題題解

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]向量

假設最後的向量是(xa+yb,za+wb)(xa+yb,za+wb) 容易發現,x,wx,wy,zy,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],表示iji~j這個數的最終矩陣是什麼,這裡是O(n2m3k)O(n^2m^3k),k是一個常數。 然後因為矩陣滿足分配率,就可以隨便求一下最終的矩陣。 然而這個複雜度很假……然而好像這樣就能過了…… 貌似有O(n2m2)O(n^2m^2)的做法。

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");
    }
}