A题:FZU 2294
这题是无符号的计算,但是有个坑就是我用printf输出一直wa,用cout输出就AC。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
using namespace std;
long long unsigned mod;
map<string,long long unsigned>m;
void init()
{
mod=1;
for(int i=1;i<=47;i++)
mod*=2;
}
int main()
{
long long unsigned num1 ;
string a,b,op;
init();
while(cin>>op)
{
if(op=="def")
{
cin>>a>>num1;
m[a]=(num1+mod)%mod;
}
else if(op=="add")
{
cin>>a>>b;
m[a]=(m[a]+m[b])%mod;
}
else if(op=="sub")
{
cin>>a>>b;
m[a]=(m[a]-m[b])%mod;
}
else if(op=="mul")
{
cin>>a>>b;
m[a]=(m[a]*m[b])%mod;
}
else if(op=="div")
{
cin>>a>>b;
m[a]=m[a]/m[b];
}
else
{
cin>>a>>b;
m[a]=m[a]%m[b];
}
cout<<a<<" = "<<m[a]<<endl;
}
}
D题:FZU 2297
这题如果把M改成质数,就是个水题n了,可惜不是,就成了一个好题,为了不丢失精度,每次D操作都得把之前所有的有效M次操作的数相乘,这样才能避免除法,这样时间复杂度是n^2,不过区间问题可用线段树优化成nlogn。单点更新,求最大的区间之积。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5;
long long mod,y,value;
long long tree[4*maxn];
void update(int L,int R,int o,int k)
{
if(L==R)
{
tree[o]=value;
return;
}
int m=(L+R)/2;
if(k<=m)
update(L,m,o*2,k);
else
update(m+1,R,o*2+1,k);
tree[o]=tree[o*2]*tree[o*2+1]%mod;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int q,i;
char op[2];
scanf("%d%lld",&q,&mod);
for(i=1;i<maxn*4;i++)
tree[i]=1;
for(i=1;i<=q;i++)
{
scanf("%s%lld",op,&y);
if(op[0]=='M')
{
value=y;
update(1,maxn,1,i);
printf("%lld\n",tree[1]);
}
else
{
value=1;
update(1,maxn,1,y);
printf("%lld\n",tree[1]);
}
}
}
}
H题:FZU 2301
题意:我有n次攻击次数,敌人有m滴血,一次攻击扣一滴血,但是我有1/2的概率攻击的不是这个敌人,求我把他杀死的概率,举个例子,n=2,m=1,假设1为攻击到敌人,0每攻击到敌人,那么有效攻击种类为10,01,11,总攻击种类有四种,那么杀死的概率就是3/4(除法用逆元)
思路:很明显我至少有m次攻击到敌人才能杀死他,那么有效攻击种类为C(m,n)+C(m+1,n)+..+C(n,n),总攻击种类有2^n,由于n最大取1000,可以提前把2^1到2^1000次方的逆元打表,也要先把∑C(i,n)(i=m,m+1,..n)的杨辉三角后缀和打表。
#include<cstdio>
#include<cstring>
using namespace std;
const int mod=1e9+7;
const int maxn=1e3+10;
long long a[maxn],b[maxn][maxn];
long long pows(long long x,int y)
{
long long res=1;
while(y)
{
if(y%2==1)
res=res*x%mod;
x=x*x%mod;
y/=2;
}
return res;
}
void init()
{
long long t=2;
for(int i=1;i<maxn;i++)
{
a[i]=pows(t,mod-2);
t=t*2%mod;
}
b[0][1]=b[1][0]=b[1][1]=1;
for(int i=2;i<maxn;i++)
{
b[i][0]=b[i][i]=1;
for(int j=1;j<i;j++)
b[i][j]=(b[i-1][j-1]+b[i-1][j])%mod;
}
for(int i=1;i<maxn;i++)
{
for(int j=i-1;j>=0;j--)
{
b[i][j]=(b[i][j]+b[i][j+1])%mod;
}
}
}
int main()
{
int T;
init();
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
if(m==0)
{
printf("1\n");
}
else if(n<m)
printf("0\n");
else
printf("%lld\n",b[n][m]*a[n]%mod);
}
}
I题用区间DP记忆化搜索,算了算复杂度为200^3竟然超时了。。。
思路:设d[ i ][ j ][ p ]为区间 i 到 j 的序列,再划分p块的最小值,那么
d[ i ][ j ][ p ]=min(sum(i, k)+dfs(k+1, j ,p-1 )),虽然超时, 但是还是奉献出代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=99999999;
int d[201][201][201],a[201],sum[201];
int n,k;
int pow(int t)
{
return t*t;
}
void init()
{
sum[0]=0;
memset(d,0,sizeof(d));
}
int dfs(int i,int j,int remain)
{
if(j-i+1<remain)
return inf;
if(remain==1)
return d[i][j][remain]=pow((sum[j]-sum[i-1]));
if(d[i][j][remain]!=0)
return d[i][j][remain];
int ans=inf;
if(i==1&&j==n)//特别注意这个序列是个环,起点和终点连在一起的
{
for(int k=2;k<n;k++)
{
for(int p=k;p<n;p++)
{
int t=dfs(k,p,remain-1)+pow(sum[k-1]+sum[n]-sum[p]);
ans=min(ans,t);
}
}
}
for(int k=i;k<j;k++)
{
int t=pow(sum[k]-sum[i-1])+dfs(k+1,j,remain-1);
ans=min(ans,t);
}
for(int k=i+1;k<=j;k++)
{
int t=dfs(i,k-1,remain-1)+pow(sum[j]-sum[k-1]);
ans=min(ans,t);
}
return d[i][j][remain]=ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int i;
scanf("%d%d",&n,&k);
init();
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
printf("%d\n",dfs(1,n,k));
}
}
J题:FZU 2303
扫描二维码关注公众号,回复:
1808458 查看本文章
思路:求一个数学期望,这题就是个推公式题。
#include<stdio.h>
const int mod=1e9+7;
const int maxn=1e6+20;
long long a[maxn];
long long pows(long long x,int y)
{
long long res=1;
while(y)
{
if(y&1)
res=res*x%mod;
x=x*x%mod;
y=(y>>1);
}
return res;
}
void init()
{
int i;
for(i=1;i<maxn;i++)
a[i]=pows(i,mod-2);
}
int main()
{
int T;
init();
scanf("%d",&T);
while(T--)
{
int n,m;
long long ans,L=1;
scanf("%d%d",&n,&m);
if(n<=m)
{
printf("%d\n",n);
continue;
}
ans=(L*m*(n+1)%mod)*a[m+1]%mod;
printf("%lld\n",ans);
}
}