Solved |
A |
B |
C |
D |
E |
F |
G |
H |
I |
J |
K |
L |
M |
5/13 |
- |
Ø |
Ø |
Ø |
- |
- |
O |
- |
- |
- |
- |
- |
O |
题目链接
https://codeforces.com/gym/102900
Problem B. Mine Sweeper II
题意:
给出两张 $n*m$ 扫雷图 $A,B$,至多修改 $B$ 中 $\lfloor\frac {nm}{2}\rfloor$ 格子,使 $B$ 中非雷格的数字之和等于 $A$。
思路:
数字和等于相邻(雷格,非雷格)二元组的个数,于是把整个地图全反过来这个二元组个数不变。
若 $A,B$ 偏差大于一半,把 $A$ 取反后 $A,B$ 偏差必不超过一半。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| #include <bits/stdc++.h> #define SZ(x) (int)(x).size() #define ALL(x) (x).begin(),(x).end() #define PB push_back #define EB emplace_back #define MP make_pair #define FI first #define SE second using namespace std; typedef double DB; typedef long long LL; typedef pair<int,int> PII; typedef vector<int> VI; typedef vector<PII> VPII;
const int N=1005; char a[N][N],b[N][N]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%s",a[i]+1); for(int i=1;i<=n;i++) scanf("%s",b[i]+1); int tot=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(a[i][j]!=b[i][j]) tot++; } } if(tot<=n*m/2) for(int i=1;i<=n;i++) printf("%s\n",a[i]+1); else { for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) putchar(a[i][j]=='X'?'.':'X'); puts(""); } } return 0; }
|
Problem C. Sum of Log
题意:
$T$ 次询问,求 $\sum_{i=0}^x\sum_{j=[i=0]}^y{[i&j=0]\lfloor\log_2{(i+j)}\rfloor+1}$。
$1\le T\le 1e5,0\le x,y\le1e9$。
思路:
在该式中,只有 $i&j=0$ 时,才会产生贡献,而此时 $i+j$ 并不会产生进位,因此 $\lfloor\log_2{(i+j)}\rfloor+1$ 为 $i+j$ 二进制表示中 $1$ 的最高位置。
需要记录四个状态:$dp_{x,a,b_1,b_2}$ ,分别为第 $x$ 位,前面是否为 $0$,前面是否是 $x$ 的上限,前面是否是 $y$ 的上限。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include <bits/stdc++.h> #define SZ(x) (int)(x).size() #define ALL(x) (x).begin(),(x).end() #define PB push_back #define EB emplace_back #define MP make_pair #define FI first #define SE second using namespace std; typedef double DB; typedef long double LD; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII; typedef vector<int> VI; typedef vector<PII> VPII;
const LL MOD=1e9+7; VI lim1,lim2; LL dp[31][2][2][2]; LL dfs(int x,bool a,bool b1,bool b2) { if(!x) return !a; if(dp[x][a][b1][b2]!=-1) return dp[x][a][b1][b2]; int mx1=b1?lim1[x]:1; int mx2=b2?lim2[x]:1; LL ret=0; for(int i=0;i<=mx1;i++) { for(int j=0;j<=mx2;j++) if(i+j!=2) { if(a&&i+j>=1) ret=(ret+1ll*x*dfs(x-1,false,b1&(i==mx1),b2&(j==mx2)))%MOD; else ret=(ret+dfs(x-1,a,b1&(i==mx1),b2&(j==mx2)))%MOD; } } return dp[x][a][b1][b2]=ret; } LL solve(int x,int y) { memset(dp,-1,sizeof dp); lim1.clear(); lim2.clear(); lim1.PB(-1); lim2.PB(-1); while(x||y) { lim1.PB(x%2); lim2.PB(y%2); x/=2; y/=2; } return dfs(SZ(lim1)-1,true,true,true); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T;cin>>T; while(T--) { int x,y;cin>>x>>y; cout<<solve(x,y)<<'\n'; } return 0; }
|
Problem D. Walker
题意:
线段上有两点以各自速度随意移动,问最少经过多久两点移动的路径能覆盖整段线段。
思路:
二分时间。
考虑如下情况:
- 某点能覆盖整段线段。
- 左边的点向右移动,右边的点向左移动。
- 左边的点向左移动,右边的点向右移动(两点可先向中间移动再折返):
- 都不先向中间移动。
- 左边的点先向中间移动再折返,右边的点向右移动。
- 右边的点先向中间移动再折返,左边的点向右移动。
- 两点都先向中间移动再折返。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #include <bits/stdc++.h> #define SZ(x) (int)(x).size() #define ALL(x) (x).begin(),(x).end() #define PB push_back #define EB emplace_back #define MP make_pair #define FI first #define SE second using namespace std; typedef double DB; typedef long long LL; typedef pair<int,int> PII; typedef vector<int> VI; typedef vector<PII> VPII;
DB n,p1,p2,v1,v2; bool check(DB t) { DB a,b; a=min(p2-p1,max(0.0,v1*t-2*p1)); b=min(p2-p1,max(0.0,v2*t-2*(n-p2))); if(v1*t>=p1&&v2*t>=n-p2&&a+b>=p2-p1) return true; if(v1*t>=p1&&v2*t>=n-p2+2*(p2-p1-a)) return true; if(v1*t>=p1+2*(p2-p1-b)&&v2*t>=n-p2) return true; a=min(p2-p1,max(0.0,(t-p1/v1)*v1/2)); b=min(p2-p1,max(0.0,(t-(n-p2)/v2)*v2/2)); if(t*v1>=p1&&t*v2>=n-p2&&a+b>=p2-p1) return true; return false; } int main() { int tt; scanf("%d",&tt); while(tt--) { scanf("%lf%lf%lf%lf%lf",&n,&p1,&v1,&p2,&v2); if(p1>p2) swap(p1,p2),swap(v1,v2); DB l=0,r=min({min(n+p1,n+n-p1)/v1,min(n+p2,n+n-p2)/v2,max((n-p1)/v1,p2/v2)}); for(int i=0;i<200;i++) { DB mid=(l+r)/2.0; if(check(mid)) r=mid; else l=mid; } printf("%.10f\n",r); } return 0; }
|
Problem G. Fibonacci
题意:
计算 $\sum_{i=1}^n\sum_{j=i+1}^ng(f_i,f_j)$。
$g(x,y)=[xy%2=0]$,$f$ 为斐波那契数。
思路:
当 $f_i,f_j$ 中至少有一个偶数时,$g(f_i,f_j)=1$,才会对答案产生贡献。
斐波那契数前 $n$ 项有 $k=\lfloor \frac n 3\rfloor$ 个偶数。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include <bits/stdc++.h> #define SZ(x) (int)(x).size() #define ALL(x) (x).begin(),(x).end() #define PB push_back #define EB emplace_back #define MP make_pair #define FI first #define SE second using namespace std; typedef double DB; typedef long long LL; typedef pair<int,int> PII; typedef vector<int> VI; typedef vector<PII> VPII;
int main() { LL n; scanf("%lld",&n); LL k=n/3; printf("%lld\n",k*(k-2+n)-k*(k-1)/2*3); return 0; }
|
Problem M. Gitignore
题意:
您的项目是一个文件夹。文件夹可以包含文件和子文件夹,没有空文件夹。
最初,git 软件将同步项目中的所有文件。但是,您可以在设置中指定一些文件和文件夹,以将它们从同步中排除。
对于 gitignore 中的每一行,您可以指定一个文件或文件夹中的所有文件。你不能忽略整个项目文件夹。
你会得到项目中所有文件的路径,以及它们是否应该被忽略。你的任务是计算 gitignore 的最小行数。
思路:
当一个文件夹内(包括所有子文件夹内)所有文件都需要排除时,则可贪心地排除这个文件夹;否则单独排除直接位于这个文件夹内需要排除的文件,并递归求解子文件夹。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| #include <bits/stdc++.h> #define SZ(x) (int)(x).size() #define ALL(x) (x).begin(),(x).end() #define PB push_back #define EB emplace_back #define MP make_pair #define FI first #define SE second using namespace std; typedef double DB; typedef long long LL; typedef pair<int,int> PII; typedef vector<int> VI; typedef vector<PII> VPII;
const int N=1e3+5; int cnt,tr[N][80],w[N]; bool st[N],vis[N][N]; VI g[N]; void insert(const string &s) { int u=1,pre=1; for(int i=0;s[i];i++) { int v=s[i]-'/'; if(!tr[u][v]) tr[u][v]=++cnt; if(!v) { if(!vis[pre][u]) { vis[pre][u]=true; g[pre].PB(u); } pre=u; } u=tr[u][v]; } vis[pre][u]=true; g[pre].PB(u); } void query(const string &s) { int u=1; for(int i=0;s[i];i++) { int v=s[i]-'/'; if(!tr[u][v]) break; if(!v) st[u]=true; u=tr[u][v]; } } void dfs(int u,int fa) { if(u!=1&&!st[u]) {w[u]=1;return;} w[u]=0; for(auto v:g[u]) dfs(v,u),w[u]+=w[v]; } int main() { int tt; scanf("%d",&tt); while(tt--) { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=cnt;i++) st[i]=false,g[i].clear(); for(int i=1;i<=cnt;i++) for(int j=1;j<=cnt;j++) vis[i][j]=false; memset(tr,0,sizeof tr); cnt=1; for(int i=1;i<=n;i++) { string s; cin>>s; insert(s); } for(int i=1;i<=m;i++) { string s; cin>>s; query(s); } dfs(1,0); printf("%d\n",w[1]); } return 0; }
|