Tishreen-CPC 2018
文章目录
题目链接:http://codeforces.com/gym/101801
A. Can Shahhoud Solve it
Problem:判断S>=D
Solution: 水题
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t,s,d;
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&s,&d);
if(s>=d) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
B. Defeat the Monsters
Problem: 每次至多消掉3个数的同一公因数,问最少需要多少次使所有数变为1
Solution: 因数分解,记录所有因子的个数,每3个加1次
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100005;
int t,n,a,cnt[maxn];
ll ans=0;
void f(int temp) {
for(int i=2; i*i<=temp; i++) {
if(temp%i==0) {
if(cnt[i]==0) ans++;
cnt[i]++;
if(cnt[i]==3) cnt[i]=0;
while(temp%i==0) {
temp/=i;
}
}
}
if(temp!=1) {
if(cnt[temp]==0) ans++;
cnt[temp]++;
if(cnt[temp]==3) cnt[temp]=0;
}
}
int main() {
scanf("%d",&t);
while(t--) {
ans=0;
memset(cnt,0,sizeof(cnt));
scanf("%d",&n);
for(int i=1; i<=n; i++) {
scanf("%d",&a);
f(a);
}
cout<<ans<<endl;
}
return 0;
}
C. UCL Game Night
Problem:给定行列n,m,找最大的子阵面积,使其中1的个数<=K
Solution: 二维前缀和,状态转移方程
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
]
+
d
p
[
i
]
[
j
−
1
]
−
d
p
[
i
−
1
]
[
j
−
1
]
+
a
[
i
]
[
j
]
dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+a[i][j]
dp[i][j]=dp[i−1][j]+dp[i][j−1]−dp[i−1][j−1]+a[i][j]
求子阵的和<=k的最大值
S
=
d
p
[
i
]
[
j
]
+
d
p
[
i
−
1
]
[
j
−
1
]
−
d
p
[
i
−
1
]
[
j
]
−
d
p
[
i
]
[
j
−
1
]
S=dp[i][j]+dp[i-1][j-1]-dp[i-1][j]-dp[i][j-1]
S=dp[i][j]+dp[i−1][j−1]−dp[i−1][j]−dp[i][j−1]
Code:
#include<bits/stdc++.h>
using namespace std;
int n,m,k,T,a[105][105],dp[105][105],ans;
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d%d%d",&n,&m,&k);
ans=0;
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
scanf("%d",&a[i][j]);
dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+a[i][j];
}
}
// for(int i=1; i<=n; i++) {
// for(int j=1; j<=m; j++) {
// cout<<dp[i][j]<<" ";
// }
// cout<<endl;
// }
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
for(int r=i; r<=n; r++) {
for(int c=j; c<=m; c++) {
if(dp[r][c]+dp[i-1][j-1]-dp[r][j-1]-dp[i-1][c]<=k) {//任意子阵的和
ans=max(ans,(r-i+1)*(c-j+1));
}
}
}
}
}
printf("%d\n",ans);
}
return 0;
}
/*
1
5 5 5
1 0 1 0 1
0 1 0 1 0
0 0 0 0 0
0 1 0 0 0
1 0 1 1 1
*/
D. Police Stations
Problem:至多建K个警局,其中每个警局有参数:
(1)P:警局离市中心距离
(2) A:警局管制范围[P-A,P+A] (该范围内不能再有其他警局)
(3) C:建造后,增加的安全度的值
(4) X: 相邻两个警局的安全度有限制条件:
∣
C
(
i
+
1
)
−
C
i
∣
≥
k
|C_(i+1)-C_i |≥k
∣C(i+1)−Ci∣≥k
求满足如上限制条件的总体安全度的最大值
Solution: 排序递归求符合要求的安全度最大值,15s,TLE了
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=10005;
ll T,n,k,p[maxn],a[maxn],c[maxn],x[maxn],ans;
struct Police{
ll p,a,c,x;
}v[maxn];
bool cmp(Police a,Police b){
return a.p<b.p;
}
ll fun(ll pr,ll temp){
if(!temp) return 0;
if(pr==n) return 0;
ll cnt=0;
for(int i=pr+1;i<=n;i++){
if(v[i].p-v[i].a<=v[pr].p||v[pr].p+v[pr].a>=v[i].p) continue;//限制条件2
if(abs(v[i].c-v[pr].c)<v[i].x) continue;//限制条件4
cnt=max(cnt,fun(i,temp-1)+v[i].c);
}
return cnt;
}
int main(){
scanf("%lld",&T);
while(T--){
ans=0;
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i++) scanf("%lld",&v[i].p);
for(int i=1;i<=n;i++) scanf("%lld",&v[i].a);
for(int i=1;i<=n;i++) scanf("%lld",&v[i].c);
for(int i=1;i<=n;i++) scanf("%lld",&v[i].x);
sort(v+1,v+n+1,cmp);
for(int i=1;i<=n;i++){
ans=max(ans,fun(i,k-1)+v[i].c);
}
printf("%lld\n",ans);
}
return 0;
}
/*
1
3 2
1 5 9
3 3 4
1 3 6
2 2 2
==7
*/
E. Create Your Own Nim Game
Problem:给定N个石头,求方案数,要求先手必赢
Solution: 根据题意,先手赢要求x不为0
X
=
S
1
(
x
o
r
)
S
2
(
x
o
r
)
.
.
.
(
x
o
r
)
S
M
X = S_1 (xor) S_2 (xor) ... (xor) S_M
X=S1(xor)S2(xor)...(xor)SM
dp [i] [j^k]: i 枚石头,X=j^k的符合要求的方案数,,有转移方程:
d
p
[
i
]
[
j
(
x
o
r
)
k
]
+
=
d
p
[
i
−
j
]
[
k
]
,
j
=
1...
i
;
;
k
=
0
,
1
,
2...
i
,
dp[i][j(xor)k]+=dp[i-j][k],j=1...i;;k=0,1,2...i,
dp[i][j(xor)k]+=dp[i−j][k],j=1...i;;k=0,1,2...i,
Code:
#include<bits/stdc++.h>
using namespace std;
const int MOD=1e9+7;
typedef long long ll;
ll dp[105][105],ans;
int n,T;
int main(){
dp[0][0]=1;
for(int i=1;i<=100;i++){
for(int j=1;j<=i;j++){
for(int k=0;k<=i;k++){
dp[i][j^k]=(dp[i][j^k]+dp[i-j][k])%MOD;
}
}
}
// for(int i=1;i<=100;i++){
// for(int j=1;j<=i;j++){
// cout<<dp[i][j]<<" ";
// }
// cout<<endl;
// }
scanf("%d",&T);
while(T--){
scanf("%d",&n);
ans=0;
for(int i=1;i<=n;i++){
ans=(ans+dp[n][i])%MOD;
}
printf("%lld\n",ans);
}
return 0;
}
F. Nim Cheater
Problem: M堆石头各Si个,问最少需要拿几个石头可以赢得比赛
Solution: 根据题意x=0后手赢,否则先手赢
X
=
S
1
x
o
r
S
2
x
o
r
.
.
.
x
o
r
S
M
X = S1 xor S2 xor ... xor SM
X=S1xorS2xor...xorSM
暴力全部xor一遍;X=0,理想状况,拿一个赢;x!=0,一定赢
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t,m,s,ans;
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&m,&ans);
for(int i=2;i<=m;i++){
scanf("%d",&s);
ans^=s;
}
if(ans) cout<<0<<endl;
else cout<<1<<endl;
}
return 0;
}