Codeforces Round #706 (Div. 1) A-D

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
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值