Pro
Sco
预计得分: 100 + 20 + 30 = 150 100 + 20 + 30 = 150 100+20+30=150
实际得分: 100 + 20 + 30 = 150 100 + 20 + 30 = 150 100+20+30=150
Sol
number
很裸的模拟题
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int len , flag , sm1 , sm2;
string d1 , d2;
int main() {
freopen("number.in","r",stdin);
freopen("number.out","w",stdout);
cin>>d1>>d2;
len = d1.length();
for(int i=0; i<len; i++) {
if(d1[i] < d2[i]) {
d1[i] = '#';
sm1++;
}
if(d1[i] > d2[i]) {
d2[i] = '#';
sm2++;
}
}
if(sm1==len)
printf("BOOM");
else {
flag = 0;
for(int i=0; i<len; i++) {
if((!flag&&d1[i]=='0')||d1[i]=='#')
continue;
flag = 1;
cout<<d1[i];
}
if(!flag)
printf("0");
}
printf("\n");
if(sm2==len)
printf("BOOM");
else {
flag = 0;
for(int i=0; i<len; i++) {
if((!flag&&d2[i]=='0')||d2[i]=='#')
continue;
flag = 1;
cout<<d2[i];
}
if(!flag)
printf("0");
}
return 0;
}
merge
打了60的DP……
#include<iostream>
#include<cstdio>
#include<cstring>
#define INF 1000000000000000000
using namespace std;
long long n , cnt[1005] , sum[1005] , dp[1005][1005] , ans = INF;
inline long long mymin(long long a , long long b) { return a<b?a:b; }
inline long long mymax(long long a , long long b) { return a>b?a:b; }
int main() {
freopen("merge.in","r",stdin);
freopen("merge.out","w",stdout);
scanf("%lld",&n);
for(int i=1; i<=n; i++) {
scanf("%lld",&cnt[i]);
cnt[i+n] = cnt[i];
}
n = 2 * n;
for(int i=1; i<=n; i++)
sum[i] = sum[i-1] + cnt[i];
for(int j=1; j<=(n-1)/2; j++)
for(int i=1; i<=n; i++) {
int len = 2*j+1;
dp[i][i+len-1] = INF;
if(len==3) {
dp[i][i+len-1] = mymin(dp[i][i+len-1] , sum[i+len-1]-sum[i-1]);
continue;
}
for(int k1=0; i+2*k1+1<=i+len-1; k1++)
for(int k2=0; i+2*k1+1+2*k2+1<=i+len-1; k2++) {
int len1 = 2*k1+1 , len2 = 2*k2+1;
if((len-len1-len2)%2)
dp[i][i+len-1] = mymin(dp[i][i+len-1] , dp[i][i+len1-1]+dp[i+len1][i+len1+len2-1]+dp[i+len1+len2][i+len-1]+sum[i+len-1]-sum[i-1]);
}
}
printf("%lld",dp[1][n/2]);
return 0;
}
problem
30分是爆搜分
#include<iostream>
#include<cstdio>
#define mod 1000000007
using namespace std;
int n , m , num[25] , vis[25];
long long ans;
void dfs(int opt) {
if(opt==n) {
ans = (ans+1)%mod;
return ;
}
if(num[opt+1])
dfs(opt+1);
else {
for(int i=1; i<=n; i++)
if(!vis[i]&&i!=opt+1) {
vis[i] = 1;
dfs(opt+1);
vis[i] = 0;
}
}
}
int main() {
freopen("problem.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++) {
int x , y;
scanf("%d%d",&x,&y);
num[y] = x;
vis[x] = 1;
}
for(int i=1; i<=n; i++)
if(!num[i]) {
for(int j=1; j<=n; j++)
if(!vis[j]&&j!=i) {
vis[j] = 1;
dfs(i);
vis[j] = 0;
}
printf("%d",ans%mod);
return 0;
}
return 0;
}
数据范围跨度好大,正解是数学做法:
按照容斥原理可得,答案 a n s = ∑ i = 0 s ( − 1 ) i C s i ( n − m − k ) ! ans=\sum_{i=0}^s (-1)^i C_{s}^{i}(n-m-k)! ans=∑i=0s(−1)iCsi(n−m−k)!
其中s表示剩下n-m个数中有s个数可能放到原来的位置。
费马小定理求逆元,预处理阶乘,求组合数什么的胡乱搞搞
#include<iostream>
#include<cstdio>
#define mod 1000000007
using namespace std;
int n , m;
long long jc[100005] , ans , s , p1[100005] , p2[100005];
inline long long mypow(long long a , long long b) {
if(!b)
return 1;
long long t = mypow(a , b/2)%mod;
if(b&1)
return ((t*t%mod)*a)%mod;
return t*t%mod;
}
inline long long inv(long long x) {
return mypow(x , mod-2)%mod;
}
void init() {
jc[1] = 1;
for(int i=2; i<=n; i++)
jc[i] = (jc[i-1]*i)%mod;
for(int i=1; i<=n; i++)
if(!p1[i]&&!p2[i])
s++;
ans = jc[n-m];
}
long long C(long long x , long long y) {
if(x<y||x==0)
return 0;
if(x==y)
return 1;
return jc[x]*inv(jc[x-y])%mod*inv(jc[y])%mod;
}
int main() {
freopen("problem.in","r",stdin);
freopen("problem.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++) {
int x , y;
scanf("%d%d",&x,&y);
p1[x] = 1;
p2[y] = 1;
}
init();
for(int i=1; i<=s; i++) {
int t1 = C(s,i);
if(i&1)
ans = (ans-C(s,i)*jc[n-m-i]%mod+mod)%mod;
else
ans = (ans+C(s,i)*jc[n-m-i]%mod)%mod;
}
printf("%lld",ans%mod);
return 0;
}