A
温暖的签到
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main(){
LL n,m,k;
scanf("%I64d%I64d%I64d",&n,&m,&k);
if( min( m,k ) >= n ){
printf("Yes");
}else{
printf("No");
}
return 0;
}
C
我们模仿KMP算法的思路,预处理子串。注意到a中相邻的两个长度为b的串的奇偶性的差异只与 子串每一位是否与前面那位 和新添加尾部的 和减少的首位 这三个元素有关。
#include <bits/stdc++.h>
using namespace std;
typedef int lint;
typedef long long LL;
int main(){
string a,b;
cin >> a>> b;
lint len = b.length();
lint flag = 0;
for( lint i = 1;i < len;i++ ){
if( b[i] != b[i-1] )flag^= 1;
}
lint flag2 = 0;
for( lint i = 0;i < len;i++ ){
if( a[i] != b[i] ) flag2^=1;
}
LL ans = 0;
if( !flag2 ) ans++;
lint len2 = a.length();
for( lint i = 1;i+len <= len2;i++ ){
flag2 ^= flag;
if( a[i+len-1] != b[len-1] ){
flag2 ^= 1;
}
if( a[i-1] != b[0] ){
flag2 ^= 1;
}
if( !flag2 ) ans++;
}
cout << ans;
return 0;
}
D
注意到上取整和下取整 对于总和的影响差值为1,所以我们不妨全部下取整,看加上几个1之后结果为0.
坑点:( double )floor( double ) 下取整
( double )ceil(double ) 上取整
STL真好用
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef int lint;
const lint maxn = 1e5 + 1;
double a[maxn],b[maxn],c[maxn];
int main(){
lint n;
double sum = 0;
scanf("%d",&n);
for( lint i = 1;i <= n;i++ ){
scanf("%lf",&a[i]);
b[i] = floor(a[i]);
c[i] = ceil(a[i]);
sum += b[i]-a[i];
}
for( lint i = 1;i <= n;i++ ){
if( abs(sum - 0) > 1e-6 ){
sum += c[i]-b[i];
if( c[i] > 0 ) c[i] += 0.1;
else c[i] -= 0.1;
printf("%I64d\n",(LL)(c[i]));
}else{
if( c[i] > 0 ) c[i] += 0.1;
else c[i] -= 0.1;
printf("%I64d\n",(LL)(b[i]));
}
}
return 0;
}
E
这题好有趣啊
我最开始的想法是将要求的矩形直接拆成一些矩形的面积并,但是发现这些整块的矩形的面积不好算。只有一些特定的矩形的面积才好算。比如面积的前缀。画个图就会发现,边长为 n * 2 ^ i( i >= 1 ) 或 边长为 m * 2 ^ i ( i >= 1 ) 的前缀矩形是对称的,其中1的个数为面积的一半。有了这个结论,那么问题就转化为求任意一个前缀矩形的面积,经过上述的拆分,最后余下的矩形一定在边长为 2* n * 2 * m 的矩形之中。这就好求了,还需要注意此时余下的矩形是以1为左上角还是以0为左上角的矩形。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef int lint;
const lint maxn = 2005;
lint a[maxn][maxn],sum[maxn][maxn];
vector<LL> ven,vem;
void prework( lint n,lint m ){
for( lint i = 1;i <= n;i++ ){
for( lint j = 1;j <= m;j++ ){
sum[i][j] = sum[i-1][j] + sum[i][j-1]-sum[i-1][j-1];
sum[i][j] += a[i][j];
}
}
ven.push_back( n );
for( ;n <= 1e9+1;n *= 2 ){
ven.push_back( n );
}
vem.push_back( m );
for( ;m <= 1e9+1;m*= 2 ){
vem.push_back(m);
}
}
LL solve( LL n,LL m,lint f ){
if( !n || ! m ) return 0;
lint p1 = upper_bound( ven.begin(),ven.end(),n ) - ven.begin();
p1--;
lint p2 = upper_bound( vem.begin(),vem.end(),m ) - vem.begin();
p2--;
if( p1 == -1&& p2 == -1 ){
if( f ){
return sum[n][m];
}
else return n*m - sum[n][m];
}
LL sum = 0;
if( p1 >= 0 ){
n -= ven[p1];
sum += ven[p1]*m/2;
return sum + solve( n,m,f^1 );
}
if( p2 >= 0 ){
m -= vem[p2];
sum += vem[p2]*n/2;
return sum + solve( n,m,f^1 );
}
}
int main(){
lint n,m,q;
scanf("%d%d%d",&n,&m,&q);
for( lint i = 1;i <= n;i++ ){
for( lint j = 1;j <= m;j++ ){
scanf("%1d",&a[i][j]);
a[i+n][j] = !a[i][j];
a[i][j+m] = !a[i][j];
a[i+n][j+m] = a[i][j];
}
}
prework((LL)2*n,(LL)2*m);
LL x1,x2,y1,y2;
for( lint i = 1;i <= q;i++ ){
scanf("%I64d%I64d%I64d%I64d",&x1,&y1,&x2,&y2);
LL ans = solve( x2,y2,1 ) - solve( x2,y1-1,1 ) - solve( x1-1,y2,1 ) + solve( x1-1,y1-1,1 );
printf("%I64d\n",ans);
}
return 0;
}
F.欧拉回路递归写法居然爆栈了。所以学到了非递归的写法。
注意到每个点最多删掉一半的边,我们新增加一个原点,将其与所有的奇度点相连接。然后跑一个欧拉回路得到一个边序列。我们把序列中下标为偶数的边删去。 一个点相邻的两边在序列中是连续的。所以每个点删掉的边数小于等于度数的一半。但是可能删掉的一半边中都是原来存在的。所以我们找到新加的边中度数为奇数的边来代替。
注意:欧拉回路的非递归写法会改变链式前向星的结构。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef int lint;
typedef pair<lint,lint> pii;
const lint maxn = 2000001;
const lint maxm = 4000001;
lint tot,ver[maxm],he[maxn],ne[maxm],id[maxm];
pii edge[maxm];
void add( lint x,lint y,lint n ){
ver[++tot] = y;
ne[tot] = he[x];
he[x] = tot;
id[tot] = n;
}
vector<lint> ans;
lint vis[maxm],v[maxn],vis2[maxm],st[maxm],re[maxm],top;
void euler( lint x ){
st[++top] = x;
while( top>0 ){
lint x = st[top];
lint cure = he[x];
while( cure && vis[cure] ) cure = ne[cure];
if( cure ){
lint y = ver[cure];
vis[cure] = vis[cure^1] = 1;
st[++top] = y;
re[top] = id[cure];
he[x] = ne[cure];
}else{
if( top != 1 )ans.push_back( re[top] );
top--;
}
}
}
vector<lint> res;
lint du[maxm];
int main(){
lint n,m;
scanf("%d%d",&n,&m);
tot = 1;
for( lint x,y,i = 1;i <= m;i++ ){
scanf("%d%d",&x,&y);
add( x,y,i );
add( y,x,i );
du[x]++;du[y]++;
edge[i].first = x;
edge[i].second = y;
}
lint totm = m;
for( lint i = 1;i <= n;i++ ){
if( du[i]&1 ){
add( 0,i,++totm );add( i,0,totm );
}
}
int res = m;
for (int i = 0; i <= n; i++) {
ans.clear();
euler(i);
for (int j = 1; j < ans.size(); j += 2) {
int now = ans[j];
if(now > m) vis2[now] = 1;
else {
int tmp = ans[j - 1];
if(tmp> m && vis2[tmp] == 0) {
vis2[tmp] = 1;
continue;
}
int Next = j + 1;
if(j == ans.size()) Next = 0;
tmp = ans[Next];
if(tmp > m && vis2[tmp] == 0) {
vis2[tmp] = 1;
continue;
}
vis2[now] = 1;
res--;
}
}
}
printf("%d\n", res );
for( lint i = 1;i <= m;i++ ){
if( vis2[i] ) continue;
printf("%d %d\n", edge[i].first,edge[i].second );
}
return 0;
}