20250814 OI 总结
Problem | T1 | T2 | T3 | T4 | T5 | T6 | all |
---|---|---|---|---|---|---|---|
want scores | 100pts | 100pts | 60pts | 40pts | 60pts | 0pts | 360pts |
scores | 100pts | 0pts | 60pts | 0pts | 60pts | 0pts | 260pts |
T3
爆零原因:输出制表符错了
正解:反向建图,这样每个点只会跑一次 dfs;
代码:(下次再也不用快读了)
#include <stdio.h>
#include <queue>
#include <vector>
#define ll long long
#define ull unsigned long long
#define int int
#define db double
using namespace std;
const int MAXN = 1e5 + 7;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int n,m;
vector<int>e[MAXN];
int dis[MAXN];
int vis[MAXN];
int read(){
int x = 0;
char ch = getchar();
while(ch < '0' || ch > '9'){ch = getchar();}
while(ch >= '0' && ch <= '9'){x=x*10+(ch-'0');ch = getchar();}
return x;
}
void dfs(int x,int root){
if(vis[x]) return;
vis[x] = root;
dis[x] = 1;
for(auto y : e[x]){
if(!dis[y]){
dfs(y,root);
}
}
}
int main(){
n = read(),m = read();
for(int i = 1;i <= m;i++){
int x,y;
x = read(),y = read();
e[y].push_back(x);
}
for(int i = n;i >= 1;i--){
dfs(i,i);
}
for(int i = 1;i <= n;i++)
printf("%d ",vis[i]);
return 0;
}
T4
死因:反转数组翻错了
思路:按照题目即可
方法总结:
- 模拟题先拟好思路在写代码
- 尽量一次写对,不然调试可是很爽的
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define int int
#define db double
const int MAXN = 50 + 7;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int t,n,k;
char s[MAXN][MAXN],c[MAXN][MAXN];
char b[MAXN][MAXN],nm[MAXN][MAXN];
void fanzhuan(){
for(int i = 1;i <= k;i++)
for(int j = 1;j <= k;j++)
b[j][k-i+1] = c[i][j];
for(int i = 1;i <= k;i++)
for(int j = 1;j <= k;j++)
c[i][j] = b[i][j];
}
bool check(int x,int y){
for(int i = 1,ii = x;i <= k;ii++,i++){
for(int j = 1,jj = y;j <= k;j++,jj++){
if(s[ii][jj] == '.' && c[i][j] == '*')
return false;
}
}
return true;
}
void draw(int x,int y){
for(int i = 1,ii = x;i <= k;ii++,i++){
for(int j = 1,jj = y;j <= k;j++,jj++){
if(c[i][j] != '.'){
nm[ii][jj] = '*';
}
}
}
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
nm[i][j] = '.';
}
}
for(int i = 1;i <= n;i++)
scanf("%s",s[i]+1);
scanf("%d",&k);
for(int i = 1;i <= k;i++)
scanf("%s",c[i]+1);
for(int i = 1;i <= n - k + 1;i++){
for(int j = 1;j <= n - k + 1;j++){
for(int l = 1;l <= 4;l++){
fanzhuan();
if(check(i,j)){
draw(i,j);
}
}
}
}
bool flag = 1;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
if(s[i][j] != nm[i][j]){
flag = 0;
break;
}
}
}
printf("%s\n",(flag) ? "YES" : "NO");
}
return 0;
}
T5
打表过样例,暴力出奇迹
死因:写完暴力没想出办法(原来写的二分,证明发现不行)
通过打表严谨分析,可以得出,只要求出顺序对的个数就好了。
代码:
#include <bits/stdc++.h>
using namespace std;
int n;
const int MAXN = 1e5 + 7;
int a[MAXN];
int c[MAXN];
long long ans = 0;
void qsort(int l,int r){
if(l == r){
return;
}
int mid = (l + r) / 2;
int i = l,j = mid + 1,k = l;
qsort(i,mid),qsort(mid+1,r);
while(i <= mid && j <= r){
if(a[i] <= a[j]){
c[k++] = a[i++];
ans += r - j + 1;
}else{
c[k++] = a[j++];
}
}
while(i <= mid){
c[k++] = a[i++];
}
while(j <= r){
c[k++] = a[j++];
}
for(int c1 = l;c1 <= r;c1++){
a[c1] = c[c1];
}
}
int k;
int main()
{
cin >> n >> k;
for(int i = 1;i <= n;i++){
cin >> a[i];
a[i] -= k;
a[i] += a[i-1];
}
qsort(0,n);
cout << ans << endl;
return 0;
}
T6
死因:最小生成树不会(虽然今天学了)
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f;
const int MAXH = 2e5 + 7;
const int mod = 1e9 + 7;
int n,m;
struct node{
int x,y,w;
bool operator < (const node &x) const{
return w < x.w;
}
}e[MAXH];
int fa[MAXH];
int c[MAXH];
int find(int x){
if(fa[x] == x)
return x;
return fa[x] = find(fa[x]);
}
int kruskal(){
for(int i = 1;i <= n;i++)
fa[i] = i;
sort(e+1,e+m+1);
int tot = n,ans = 0;
for(int i = 1;i <= m;i++){
int x = find(e[i].x),y = find(e[i].y);
if(x != y){
ans += e[i].w;
tot--;
fa[x] = y;
}
}
return ans;
}
signed main()
{
cin >> n >> m;
int s = INF;
for(int i = 1;i <= n;i++){
cin >> c[i];
s = min(s,c[i]);
}
for(int i = 1;i <= m;i++){
cin >> e[i].x >> e[i].y >> e[i].w;
e[i].w += e[i].w;
e[i].w += c[e[i].x] + c[e[i].y];
}
int ans = kruskal();
cout << ans + s;
return 0;
}