您的位置:首页 > 其它

poj3695&bzoj1853 容斥定理

2015-06-02 00:14 281 查看
容斥定理的几个实际应用:

1、求几个矩形的面积并 题目poj3695

2、求一个区间【l,r】内是a1、a2、—-an倍数的数的总数 题目bzoj 1853

3、求一个区间[l,r]与m互质的数的个数

(第三点区间个数为r-l+1,先将m分解质因数a1,a2—an个,求出区间[l,r]内是a1,a2—an倍数的数的总数sum,r-l+1-sum即所与m互质的数的总数) 题目poj1091

poj3695

题意:给出n个矩形,每次询问若干个矩阵的面积并。

在这里由于线段树太伤了,所以就不用这个方法了~~改用面积并。

遍历一次并操作,维护符合的询问即可

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include<string.h>
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;
#define exp 1e-8
#define INF 0x3f3f3f3f
#define ll long long
#define set(a,b) memset(a,b,sizeof(a));
#define set(a,b) memset(a,b,sizeof(a));
#define for1(a,b) for(int a=1;a<=b;a++)//1---(b)
#define for0(a,b) for(int a=0;a<=b;a++)//0---(b)
void bug(string st="bug")
{cout<<st<<endl;}
template<typename __ll>
inline void READ(__ll &m){
__ll x=0,f=1;char ch=getchar();
while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
m=x*f;
}
template<typename __ll>
inline void read(__ll &m){READ(m);}
template<typename __ll>
inline void read(__ll &m,__ll &a){READ(m);READ(a);}
template<typename __ll>
inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}
struct dat
{
int x1,y1,x2,y2;
}d[22];
int s[1111111+10];
int aks[1111111+10];
int n,m,cmd,k;
void dfs(int x1=0,int y1=0,int x2=10001,int y2=10001,int deep=0,int flag=-1,int sta=0)
{
if(x1>=x2||y1>=y2)return ;
if(deep==n)
{
if(sta) //选了
{
for1(i,m)
if((sta|aks[i])==aks[i])
s[aks[i]]+=flag*(x2-x1)*(y2-y1);
}
return ;
}
dfs(x1,y1,x2,y2,deep+1,flag,sta);
dfs(max(x1,d[deep+1].x1),max(y1,d[deep+1].y1),min(x2,d[deep+1].x2),min(y2,d[deep+1].y2),deep+1,-flag,sta|(1<<deep));
}
int main()
{
int cas=1;
while(scanf("%d %d",&n,&m),n+m)
{
set(aks,0);
set(s,0);
for1(i,n)read(d[i].x1,d[i].y1),read(d[i].x2,d[i].y2);
for1(i,m)
{
read(cmd);
while(cmd--)
{
read(k);
aks[i]|=(1<<(k-1));
}
}
dfs();
printf("Case %d:\n",cas++);
for1(i,m)
printf("Query %d: %d\n",i,s[aks[i]]);
printf("\n");
}
return 0;
}


bzoj 1853

题意:求若干幸运数在一个区间的倍数的总数

很明显是容斥定理

这里要注意,生成的数先优化一下,去掉自相为倍数的数

遍历从大到小遍历,可以省去很多无用的遍历

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include<string.h>
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;
#define exp 1e-8
#define INF 10000000000
#define ll long long
#define ull unsigned long long int
#define set(a,b) memset(a,b,sizeof(a));
#define set(a,b) memset(a,b,sizeof(a));
#define for1(a,b) for(int a=1;a<=b;a++)//1---(b)
#define for0(a,b) for(int a=0;a<=b;a++)//0---(b)
void bug(string st="bug")
{cout<<st<<endl;}
template<typename __ll>
inline void READ(__ll &m){
__ll x=0,f=1;char ch=getchar();
while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
m=x*f;
}
template<typename __ll>
inline void read(__ll &m){READ(m);}
template<typename __ll>
inline void read(__ll &m,__ll &a){READ(m);READ(a);}
template<typename __ll>
inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}
ull num[100000];
ull b[100000];
bool vis[100000];
int cnt=0;
int n=0;
ull ans=0;
ull l,r;
void dfs1(ull sum)
{
if(sum>r)return;
num[++cnt]=sum;
dfs1(sum*10+6);
dfs1(sum*10+8);
}
void dfs2(int deep=n,int flag=-1,ull sta=1)
{
if(!deep)  //遍历完毕
{
if(sta!=1)  //如果选择了~~
ans+=flag*(r/sta-(l-1)/sta);
return ;
}
dfs2(deep-1,flag,sta);  //不选择
ull tmp=sta/__gcd(sta,num[deep]);
if((double)tmp*num[deep]<=r)  //加一个条件
dfs2(deep-1,-flag,tmp*num[deep]);  //选择
}
int main()
{
read(l,r);
dfs1(6);
dfs1(8);
sort(num+1,num+1+cnt);
for1(i,cnt)  //一个小小的优化,去掉同倍数的值
if(!vis[i])
{
b[++n]=num[i];
for(int j=i+1;j<=cnt;j++)
if(num[j]%num[i]==0)
vis[j]=1;
}
for1(i,n)
num[i]=b[i];
dfs2();
printf("%lld",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: