B题不会结果据说4*4的有问题然后被删了……
E题是一个01矩阵找规律,
F题是一个欧拉图的构造之后删边,但可以用顶点的度贪心过
https://www.cnblogs.com/hfctf0210/p/11104352.html
两个01串a和b,|b|<=|a|<=1e6,
求a的所有长度为b的子串中,和b对应位置不同的总个数为偶数的串c的数量
据说可以FFT做然而不知道怎么做,就是前缀和/尺取做就好
如果c和b的1的数量相同,则无论如何,二者的diff数量都为偶数
把1和1,0和0对应的去掉,剩下只要有一个1对应0 就有一个0对应1,必为偶数
所以,只需统计c和b的1的数量差即可,前缀和作差
#include
using namespace std;
const int maxn=1e6+10;
char a[maxn],b[maxn];
int ans,sum[maxn];
int lena,lenb;
int cnta,cntb;
int main()
{
scanf("%s%s",a+1,b+1);
lena=strlen(a+1);
lenb=strlen(b+1);
for(int i=1;i<=lena;++i)
sum[i]=sum[i-1]+(a[i]=='1');
for(int i=1;i<=lenb;++i)
cntb+=b[i]=='1';
for(int i=lenb;i<=lena;++i)
{
cnta=sum[i]-sum[i-lenb];
if((cnta-cntb)%2==0)ans++;
}
printf("%d\n",ans);
return 0;
}
给你一个n*m(1<=n,m<=1e3)的01矩阵A,其左上角顶点为(1,1),右下角顶点为(n,m)
将矩阵A所有位取反,构成新矩阵记为B,
A右边放一个B,下面放一个B,右下放一个A,构成新矩阵
AB
BA
将这个矩阵定义为新矩阵C,然后重复这个过程,不断扩展,至铺满二维平面……
以下q(q<=1e5)个询问,每次询问四元组(x1,y1,x2,y2),代表两个点的坐标
要求询问左上角顶点为(x1,y1),右下角为(x2,y2)的矩形内1的个数,
考虑二维dp,这样变成了只需统计四元组(1,1,x,y)的答案的数量,
记|A|代表A所代表的矩阵的1的数量,
引理1:把A和B的矩阵对应位置相加,则所有位置均为1,
所以|A|+|B|=n*m,有其面积之和等于1的数量的二倍
那么把矩阵扩成2n*2m的矩阵,开dp[2*maxn][2*maxm]统计答案
对于(x,y)的询问,把面积分为四部分,
①是完整的2n*2m块,
对于②内每一块,每个块内n*1的竖条,其下面的n*1的竖条都是它的取反,
同理对于③内每一块,每个块内1*m的横块,其右边1*m的横块都是它的取反,
所以①、②、③都符合引理1,ll res=(1ll*x*y-1ll*(x%n)*(y%m))/2;
去判断④的面积,只需判断④所在矩阵是A还是B,
引理2:记bitcnt(x)为x的二进制表示下1的数量,则对于(x,y)所在的块号P(x/n,y/m)
若bitcnt(x/n)+bitcnt(y/m)为奇数,则(x,y)处于矩阵B中,否则(x,y)处于矩阵A中
证明考虑把A矩阵记做0,B矩阵记做1,先考虑一维的复制过程
①一个一个invert,0->01 ②两个两个invert,01->0110 ③四个四个invert,0110->01101001
这样看看不出来什么,但是如果把②中的01两位看作0,则②也是0->01的过程
那么,比如(x/n,y/m)为(7,7)的情形,由于7=二进制(111),
最高位1说明,在四个四个invert的过程中,7位于右侧即invert矩阵内,再invert一次之后与3相同
同理第二个1说明,两个两个invert的过程中,7位于右侧即invert矩阵内,再invert一次之后与1相同
而最低位的1说明,7处于原矩阵内,没有被invert,处于1的位置的是原矩阵
刚才是逆向考虑的,考虑从原矩阵invert到7的过程,invert了两次,
那么行和列这个过程是独立的,只需统计invert奇数次还是偶数次即可,
实际invert的次数是bitcnt(x/n)+bitcnt(y/m)-2,所以考虑二者之和的奇偶性即可
如果位于B矩阵,④的面积就是(x%n)*(y%m)-dp[x%n][y%m];
否则位于A矩阵,面积为dp[x%n][y%m]
#include
using namespace std;
typedef long long ll;
const int N=1e3+10;
int n,m,q;
int dp[2*N][2*N];
char s[N];
int x1,x2,y1,y2;
ll cal(int x,int y)
{
ll res=(1ll*x*y-1ll*(x%n)*(y%m))/2;
int pos=(x/n)^(y/m),num=0;
for(;pos;pos>>=1)
num+=(pos&1);
if(num&1)res+=(x%n)*(y%m)-dp[x%n][y%m];
else res+=dp[x%n][y%m];
return res;
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;++i)
{
scanf("%s",s+1);
for(int j=1;j<=m;++j)
{
dp[i][j]=(s[j]=='1');
dp[i+n][j+m]=dp[i][j];
dp[i+n][j]=dp[i][j+m]=dp[i][j]^1;
}
}
n*=2;m*=2;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
dp[i][j]+=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1];
}
while(q--)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
printf("%lld\n",cal(x2,y2)-cal(x1-1,y2)-cal(x2,y1-1)+cal(x1-1,y1-1));
}
return 0;
}
还是要习惯图论构图的数组写法,简单快捷
给一个n点m边(1<=n<=1e6,0<=m<=1e6)的简单图,第i个点的度为di
在保留不超过(n+m)/2条边(向上取整)的条件下,要求新的图中每个的点的度fi>=di/2(向上取整)
输出最后保留的边的条数,和每条边的u、v
让每个点的最终的度fi为第二行左式,
考虑到di为偶数时分子+1向下取整不变,为奇数时分子+1相当于向上取整,会比直接除以2的值大1;
那么全为偶数就相当于+0,全为奇数相当于+n,故<=第二行中式
由于存在向下取整,显然<=第二行右式,
这样只需贪心地从小考虑当前度没有删到fi的点,把多余的边删掉即可
考虑欧拉图的充要条件,所有点都是偶度的节点即偶结点
这样由于有偶数个奇节点(总度数为偶数),把这些节点统统连向虚节点0构成一个菊花图,
则所有奇结点的度变为偶数,且0的度为偶数,是一个欧拉图
寻找欧拉回路,把这条路径上标号为偶数的边删掉,如果最后是奇数条边就把最后一条留下
这样连在同一个点上的边,每两条边才会删一条,所以剩下的度至少是原度的一半
再考虑删去虚节点0之后的情形,3号节点可能没有度,是因为3号和4号这两条边实际是不存在的
那就在删实际边2号边的过程中,考虑其欧拉回路序列的前驱1号边和3号边,
如果有虚边,则优先删虚边,即什么也不操作,保留2号边
特别地,在这个欧拉回路中,认为4号边的后继为1号边
两条实际边不会删同一条虚边,
例如2-3-4-5,其中2-3是实边,3-4是虚边,4-5是实边,则3和4都是实点,与虚边矛盾
代码还是看官方题解叭,感觉这题从这个方向考虑很秀啊
#include
using namespace std;
const int N=1e6+10;
struct node{int id,d;};//(节点,度)
bool operator<(node a,node b){return a.d>b.d;}
int edge,ans;
int n,m;
int deg[N],now[N];
int U[N],V[N];
int v[N*2],nex[N*2],w[N*2],head[N],cnt;
bool del[N],vis[N];
priority_queueq;
void add(int x,int y,int z)
{
v[++cnt]=y;
nex[cnt]=head[x];
w[cnt]=z;
head[x]=cnt;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
scanf("%d%d",&U[i],&V[i]);
add(U[i],V[i],i);
add(V[i],U[i],i);
deg[U[i]]++;
deg[V[i]]++;
}
for(int i=1;i<=n;++i)
{
now[i]=deg[i];
q.push((node){i,now[i]});
}
edge=m;
while(!q.empty())
{
if(edge<=(n+m+1)/2)break;
int x=q.top().id;
q.pop();
if(vis[x])continue;
vis[x]=1;
for(int i=head[x];i&&now[x]!=(deg[x]+1)/2;i=nex[i])
{
int y=v[i];
if(!del[w[i]]&&now[y]!=(deg[y]+1)/2)
{
now[x]--;
now[y]--;
edge--;
del[w[i]]=1;
q.push((node){y,now[y]});
}
}
}
for(int i=1;i<=m;++i)
if(!del[i])ans++;
printf("%d\n",ans);
for(int i=1;i<=m;++i)
if(!del[i])printf("%d %d\n",U[i],V[i]);
return 0;
}