第九屆福建省大學生程式設計競賽 部分題解
阿新 • • 發佈:2018-12-24
這題是無符號的計算,但是有個坑就是我用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; } }
這題如果把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]); } } } }
題意:我有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));
}
}
思路:求一個數學期望,這題就是個推公式題。
#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);
}
}