A
发现只用看绝对值,而且是小的跟小的配,大的跟大的配,否则就会形成蝴蝶的形状,两边之和大于第三边,不划算(图画一画)
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const long double inf = 1e9;
inline int rd() {
int p = 0; int f = 1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
long double a[N],b[N]; int alen,blen;
signed main() {
// ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int t = rd();
while(t--) {
int n = rd(); long double s = 0;
alen = blen = 0;
for(int i=1;i<=n*2;i++) {
int x = rd() ,y = rd();
if(x == 0) b[++blen] = abs(y);
else a[++alen] = abs(x);
}
sort(a+1,a+alen+1);
sort(b+1,b+blen+1);
for(int i=1;i<=alen;i++) {
// cout << a[i] << " " << b[blen - i +1] << endl;
s = s + sqrt(a[i] * a[i] + b[i] * b[i]);
}
printf("%.12Lf\n",s);
}
}
B
是个爬山博弈问题,一层一层找结论:
1、只用 Qingshan 在凸峰(两边都是下坡)的情况,不然直接在下坡一格堵住即可
2、两段坡的长度一定要相等,并且长度都要为偶数。
假设坡长相差大于等于1,肯定可以在奇数坡长的地方堵住 Qingshan,那么如果相等,因为 Qingshan 是先手,所以长度一定要是偶数,Daniel 一定要在凹峰开始堵。
3、还有就是 Daniel 不堵,而是往更长的,另外的上升坡上跑了
#include <bits/stdc++.h>
#define MP make_pair
#define int long long
using namespace std;
const int N = 2e5 + 10;
const long double inf = 1e9;
inline int rd() {
int p = 0; int f = 1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
int a[N]; int alen;
int maxl[N],maxr[N],minl[N],minr[N];
pair<int,int> pr[N]; int len = 0;
bool cmp(const pair<int,int> &x,const pair<int,int> &y) {
if(abs(x.second) != abs(y.second)) return abs(x.second) > abs(y.second);
return x.first < y.first;
}
signed main() {
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
// ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
// int t = rd();
// while(t--) {
int n = rd();
for(int i=1;i<=n;i++) a[i] = rd(); int s = 0;
for(int i=1;i<=n;i++) if(i == 1 || i == n || (a[i] > a[i-1] && a[i] > a[i+1]) || (a[i] < a[i-1] && a[i] < a[i+1]) ){
int l = i; while(a[l] > a[l-1] && l > 1) l --;
int r = i; while(a[r] > a[r+1] && r < n) r ++;
// printf("%lld %lld %lld\n",i,l,r);
maxl[i] = i - l; maxr[i] = r - i;
l = i; while(a[l] < a[l-1] && l > 1) l --;
r = i; while(a[r] < a[r+1] && r < n) r ++;
minl[i] = i - l; minr[i] = r - i;
pr[++len] = MP(i , -minl[i]);
pr[++len] = MP(i , minr[i]);
}
sort(pr+1,pr+len+1,cmp);
// for(int i=1;i<=len;i++) printf("%lld %lld\n",pr[i].first,pr[i].second);
for(int i=1;i<=n;i++) if(maxl[i] == maxr[i] && (maxl[i] % 2 == 0) && maxl[i] > 0) {
bool bk = 1;
for(int j=1;j<=len;j++) {
if(abs(pr[j].second) < maxl[i]) break;
else {
if(pr[j].first + pr[j].second == i) continue;
else{bk = 0; break;}
}
}
if(bk) s++;
}
// assert(s <= 1);
printf("%lld\n",s);
// }
}
/*
7
1 2 5 4 3 6 7
*/
C
假设发现了。。可以隔三个一组的话,事情就非常好办了
将 j = 1、4、…、m%3==1 的列都提出来,然后全画上 X
发现 j = 2 、j = 3 只要有一处稍微延长一点就好了
后面可能会剩下两列,直接从 j = 1 、4、…、m%3 == 1的列连过去两格即可
#include <bits/stdc++.h>
#define MP make_pair
#define int long long
using namespace std;
const int N = 5e2 + 10;
const int inf = 1e9;
const int mod = 998244353;
inline int rd() {
int p = 0; int f = 1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
char ch[N][N],ans[N][N];
signed main() {
int t = rd();
while(t--) {
int n = rd() , m = rd();
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("\n%c",&ch[i][j]);
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ans[i][j] = ch[i][j];
int lst;
for(int j=1;j<=m;j++) {
if(j % 3 == 1) {
for(int i=1;i<=n;i++) ans[i][j] = 'X';
if(j!=1) for(int i=j-1;i%3!=1;i--) ans[lst][i] = 'X';
lst = 1;
}
else if(j == m) {
if(j % 3 == 0) {
for(int i=1;i<=n;i++) if(ch[i][j] == 'X') ans[i][j-1] = ans[i][j] = 'X';
}else {
for(int i=1;i<=n;i++) if(ch[i][j] == 'X') ans[i][j] = 'X';
}
}
else {
for(int i=1;i<=n;i++) if(ch[i][j] == 'X') ans[i][j] = 'X',lst = i;
}
}
for(int i=1;i<=n;i++){for(int j=1;j<=m;j++) printf("%c",ans[i][j]); puts("");}
}
}
/*
5
3 3
X.X
...
X.X
4 4
....
.X.X
....
.X.X
5 5
.X...
....X
.X...
.....
X.X.X
1 10
....X.X.X.
2 2
..
..
*/
D
考虑只有一个根怎么做,就从距离小到距离大开始弄,对于每个点 v,如果有
f
[
u
]
[
v
]
=
f
[
u
]
[
i
]
+
f
[
i
]
[
v
]
f[u][v] = f[u][i] + f[i][v]
f[u][v]=f[u][i]+f[i][v] 成立,那么i就可以向v连边,每个点的方案数相乘就是答案。
两个根怎么做,之间的路径有且仅有一条,万一有多个点满足
f
[
u
]
[
i
]
+
f
[
i
]
[
v
]
=
f
[
u
]
[
v
]
f[u][i] + f[i][v] = f[u][v]
f[u][i]+f[i][v]=f[u][v] 就不行
中间的节点弄完后,剩下的结点只用像前一种方案那样判断就好了,两个顶点都要判断。
#include <bits/stdc++.h>
#define MP make_pair
#define int long long
using namespace std;
const int N = 4e2 + 10;
const int inf = 1e9;
const int mod = 998244353;
inline int rd() {
int p = 0; int f = 1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
int f[N][N],w[N][N],cnt[N];
vector<int> g[N];
signed main() {
int n = rd(); int m = rd(); memset(w,63,sizeof(w)); memset(f,63,sizeof(f));
for(int i=1;i<=m;i++) {
int x = rd(); int y = rd();
f[x][y] = f[y][x] = w[x][y] = w[y][x] = 1;
g[x].push_back(y); g[y].push_back(x);
}
for(int i=1;i<=n;i++) f[i][i] = 0;
for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j] = min(f[i][k] + f[k][j] , f[i][j]);
// for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cout << f[i][j] << " \n"[j==n];
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
int s = 1;
for(int k=1;k<=n;k++) cnt[k] = 0;
for(int k=1;k<=n;k++) if(f[i][k] + f[k][j] == f[i][j] && f[i][k] < n) cnt[f[i][k]] ++;
if(f[i][j] < n){for(int k=1;k<=f[i][j];k++) if(cnt[k] != 1) s = 0;} else s = 0;
if(s) {
int tmp = 0;
for(int k=1;k<=n;k++) {
if(f[i][k] > inf || f[j][k] > inf) tmp = 0;
else if(f[i][k] + f[k][j] != f[i][j]) {
tmp = 0;
// cout << i << " " << j << " " << k << endl;
for(auto u:g[k]) if(f[i][u] + w[u][k] == f[i][k] && f[j][u] + w[u][k] == f[j][k]) tmp++;
}
else tmp = 1;
// cout << "! " << tmp << endl;
s = s * tmp % mod;
}
}
cout << s << " \n"[j==n];
}
}
}
/*
5
1 4 2 5 3
*/