haoi部分水題題解
阿新 • • 發佈:2018-12-10
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]向量
假設最後的向量是 容易發現,或的和都是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。
先預處理出,表示這個數的最終矩陣是什麼,這裡是,k是一個常數。
然後因為矩陣滿足分配率,就可以隨便求一下最終的矩陣。
然而這個複雜度很假……然而好像這樣就能過了……
貌似有的做法。
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");
}
}