[CF]Codeforces Round #532 (Div. 2)
不要问我为什么都cfr534了才发532 orz
https://codeforces.com/contest/1100
官方TJ
A
水题模拟#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int n,k;
int a[105];
int solve(int b) {
int cc = 0;
for(int i=1;i<=n;i++){
if( abs(i-b)%k==0) continue;
cc += a[i];
}
return abs(cc);
}
int main() {
cin>>n>>k;
for(int i=1;i<=n;i++) {
cin>>a[i];
}
int ans = 0;
for(int b=0;b<k;b++){
ans = max(ans,solve(b));
}
cout<<ans;
}
B
水题模拟#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 2e5+5;
int n,m;
int ff[maxn];
int cc;
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
int x; scanf("%d",&x);
ff[x]++; if(ff[x]==1) cc++;
if(cc==n) {
putchar('1');
for(int i=1;i<=n;i++) {
ff[i]--;
if(ff[i]==0) cc--;
}
}else putchar('0');
}
}
C
水题,幼儿园数学#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef double db;
const db pi = acos(-1);
const int maxn = 2e5+5;
int n;db r,si;
int main() {
cin>>n>>r;
si = pi/n;
si = sin(si);
printf("%.10f",si/(1-si)*r);
}
D
一个999*999的棋盘,车子国王交替行动,国王只能一步(横竖斜)移动,对面有666个车,如果国王走到一个点(不能有车),那一横行有车或者纵列有车,那么国王赢,否则2000回合后车子赢。车子可以选择其中一个车,任意全场走。 十分考思维的一道题。一种构造方案是将国王移动到期盘中央。这样就把棋盘分割成了4块。如果我们往其中一个角落走,就有三块的车子必须要移动。选择角落,考虑根据鸽巢原理,至少要移动500个棋,而你只用走499步,就刚刚好了。 对于这样数字、图形固定的交互题可以考虑到从数字和鸽子原理性质下手。#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
int vis[1005][1005];
void fls(int x,int y) {
printf("%d %d\n",x,y);
fflush(stdout);
}
int wx[1005],wy[1005];
void getit() {
int k,x,y; scanf("%d%d%d",&k,&x,&y);
if(k+x+y==-3||k+x+y==0) exit(0);
vis[wx[k]][wy[k]] = 0;
wx[k] = x; wy[k] = y;
vis[wx[k]][wy[k]] = 1;
}
int X,Y;
int DX[5] = {0,-1,-1,1,1};
int DY[5] = {0,-1,1,1,-1};
void move(int dx,int dy) {
X += dx; Y += dy;
if(vis[X][Y]) X-=dx;
fls(X,Y);
getit();
}
int sm[5],SUM[5];
int main() {
scanf("%d%d",&X,&Y);
for(int i=1;i<=666;i++) {
int x,y; scanf("%d%d",&x,&y);
wx[i] = x; wy[i] = y;
vis[x][y] = 1;
}
while(X<500) move(1,0);
while(X>500) move(-1,0);
while(Y<500) move(0,1);
while(Y>500) move(0,-1);
for(int i=1;i<=499;i++) for(int j=1;j<=499;j++) sm[1] += vis[i][j];
for(int i=1;i<=499;i++) for(int j=501;j<=999;j++) sm[2] += vis[i][j];
for(int i=501;i<=999;i++) for(int j=501;j<=999;j++) sm[3] += vis[i][j];
for(int i=501;i<=999;i++) for(int j=1;j<=499;j++) sm[4] += vis[i][j];
SUM[1] = sm[1] + sm[2] + sm[4];
SUM[2] = sm[1] + sm[2] + sm[3];
SUM[3] = sm[2] + sm[3] + sm[4];
SUM[4] = sm[1] + sm[3] + sm[4];
int TO = 1;
for(int i=2;i<=4;i++) if(SUM[i]>SUM[TO]) TO = i;
while(move(DX[TO],DY[TO]),1);
}
E
就是一张有向图,你可以为一些边定向,代价为这些边的最大边权,用最小代价并给出方案使得图没环。 很有意思的一道题,但其实这种定向问题我在hzwer的无向图的时候已经遇到过一次了,再遇到一次我居然还能做错,,,真是感觉没救了T_T,很容易想到二分。二分之后将所有边权小于二分值的边删掉,利用剩下的有向图拓扑,如果没环就可行。 之后相当于无向图定向问题,直接按着拓扑序连边就可以了。#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 2e5+5;
int en[maxn],nt[maxn],la[maxn],len[maxn],owo;
void adg(int x,int y,int z) {
en[++owo] = y; nt[owo] = la[x]; la[x] = owo; len[owo] = z;
}
int n,m;
int ha[maxn],cnt;
int ID[maxn],dfx;
int in[maxn];
int qe[maxn],ql,qr;
bool isok(int C) {
ql = 1; qr = 0;
fill(in+1,in+1+n,0);
for(int i=1;i<=n;i++) {
for(int it=la[i];it;it=nt[it]) {
int y = en[it];
if(len[it]>C) {
in[y]++;
}
}
}
for(int i=1;i<=n;i++) {
if(!in[i]) qe[++qr] = i;
} dfx = 0;
while(ql<=qr) {
int x = qe[ql++];
ID[x] = ++dfx;
for(int it=la[x];it;it=nt[it]) {
int y = en[it];
if(len[it]>C&&( (--in[y])==0)) qe[++qr] = y;
}
}
return dfx == n;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
int x,y,z; scanf("%d%d%d",&x,&y,&z);
adg(x,y,z); ha[++cnt] = z;
}
ha[++cnt] = 0;
sort(ha+1,ha+1+cnt);
cnt = unique(ha+1,ha+1+cnt)-ha-1;
int L = 1; int R = cnt ,mid,ans = 0;
while(L<=R) {
mid = (L+R)>>1;
if(isok(ha[mid])) ans = ha[mid],R=mid-1;
else L = mid + 1;
}
isok(ans);
int K = 0; ql = 1; qr = 0;
for(int i=1;i<=n;i++) {
for(int it=la[i];it;it=nt[it]) {
if(len[it]<=ans&&ID[i]>ID[en[it]]) {
qe[++qr] = it;
}
}
}
printf("%d %d\n",ans,qr);
while(ql<=qr) {
printf("%d ",qe[ql++]);
}
}
F
n 5e5 区间选择若干个数,使得他们的异或和最大。 可以考虑到线性基,但只想到线段树维护线性基或者cdq维护线性基,这样nlog^2n显然要g。 后来发现可以离线之后在线性基上维护一个时间,按照时间插入一个向量,发现一个与之线性相关的基的时候,不是消除掉这一维,而是替换,然后消除掉这一维,尽量用时间后的替换前的。这样扫描到右端点的时候,所有在左端点右边的数都可以作为线性基基底。#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define pr pair<int,int>
using namespace std;
int n,q;
int JI[25],TM[25];
vector<pr>ve[500005];
int A[500005];
int getmax(int tim) {
int ans = 0;
for(int i=19;i>=0;i--) {
if(TM[i]>=tim) {
if((ans^JI[i])>ans) ans = ans ^ JI[i];
}
}
return ans;
}
void ins(int tim,int x) {
for(int i=19;i>=0;i--) {
if((x>>i)&1) {
if(!JI[i]) { JI[i] = x; TM[i] = tim; return; }
if(tim>TM[i]) {
swap(JI[i],x); swap(tim,TM[i]);
}
x^=JI[i];
}
}
}
int ANS[500005];
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) {
int x; scanf("%d",&x);
A[i] = x;
}
scanf("%d",&q);
for(int i=1;i<=q;i++) {
int l,r; scanf("%d%d",&l,&r);
ve[r].push_back(pr(i,l));
}
for(int i=1;i<=n;i++) {
ins(i,A[i]);
for(auto p:ve[i]) {
ANS[p.first] = getmax(p.second);
}
}
for(int i=1;i<=q;i++) {
printf("%d\n",ANS[i]);
}
}