官方题解:http://blog.sina.com.cn/s/blog_15139f1a10102vnx5.html
1001
HDU 5288:http://acm.hdu.edu.cn/showproblem.php?pid=5288
题意:给出一个数组\(a[n]\),定义函数\(f(l,r)\)表示在区间\([l,r]\)内没有\(a_i\)的因子的\(i\)的数量,因子的下标不能为\(i\),求
$$\sum_{i=1}^{n}\sum_{j=i}^{n}f(i,j)\mod(10^9+1)$$
题目可以转换成每个\(a_i\)可以贡献的区间个数为\(K_i\),求出所有\(K_i\)之和
要求\(K_i\)就是找左右离\(a_i\)最近的2个因子,求出左右不包含因子的区间长度\(l,r\)
$$K_i=(l+1)\times (r+1)$$
$$ans=\sum_{i=1}^{n}K_i$$
要求出最近的因子可以预处理10000内所有数的因数,在输入的时候记录每个数出现的位置,因为记录是有序的,所以可以找出离\(a_i\)最近的两个因子
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define LL __int64
#define N 100005
#define M 10005
#define INF 1<<30
#define MOD 1000000007
int n;
int a[N];
vector<int> fac[M];
vector<int> sit[M];
void init(){
for(int i=1;i<M;++i){
for(int j=i;j<M;j+=i){
fac[j].push_back(i);
}
}
}
int main(){
init();
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=10000;i++)
sit[i].clear();
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
sit[a[i]].push_back(i);
}
LL ans=0;
LL ll,rr;
int flag;
for(int i=1;i<=n;++i){
ll=0,rr=n+1;
for(int j=0;j<fac[a[i]].size();++j){
flag=1;
for(int k=0;k<sit[fac[a[i]][j]].size();++k){
if(sit[fac[a[i]][j]][k]<i){
ll=MAX(ll,sit[fac[a[i]][j]][k]);
}
if(sit[fac[a[i]][j]][k]==i)continue;
if(sit[fac[a[i]][j]][k]>i){
rr=MIN(rr,sit[fac[a[i]][j]][k]);
break;
}
}
}
ll=i-ll-1;
rr=rr-i-1;
ans=(ans+(ll+1)*(rr+1))%MOD;
}
printf("%I64d\n",(ans)%MOD);
}
return 0;
}
1002
HDU 5289:http://acm.hdu.edu.cn/showproblem.php?pid=5289
题意:求区间内的数两两之间差小于K的区间个数
RMQ+二分
先预处理出区间最大值和最小值
对于每个\(a_i\)可以用二分找出最大的r值满足区间[i,r]的最大值-最小值<K
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define LL __int64
#define INF 1<<30
const int MAXN = 100010;
int dp1[MAXN][20];
int dp2[MAXN][20];
int mm[MAXN];
//初始化RMQ, b数组下标从1开始
void initRMQ(int n,int b[]) {
mm[0] = -1;
for(int i = 1; i <= n; i++) {
mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
dp1[i][0] = b[i];
dp2[i][0] = b[i];
}
for(int j = 1; j <= mm[n]; j++)
for(int i = 1; i + (1<<j) -1 <= n; i++){
dp1[i][j] = max(dp1[i][j-1],dp1[i+(1<<(j-1))][j-1]);
dp2[i][j] = min(dp2[i][j-1],dp2[i+(1<<(j-1))][j-1]);
}
}
//查询最大值
int rmq1(int x,int y) {
int k = mm[y-x+1];
return max(dp1[x][k],dp1[y-(1<<k)+1][k]);
}
//查询最小值
int rmq2(int x,int y) {
int k = mm[y-x+1];
return min(dp2[x][k],dp2[y-(1<<k)+1][k]);
}
int n,k;
int a[MAXN];
bool judge(int x,int y){
if(rmq1(x,y)-rmq2(x,y)<k)
return true;
return false;
}
int main() {
int T;
scanf("%d",&T);
int l,r,m;
LL ans;
while(T--){
scanf("%d%d",&n,&k);
ans=0;
for(int i=1;i<=n;++i)scanf("%d",&a[i]);
initRMQ(n,a);
for(int i=1;i<=n;++i){
l=i,r=n;
int e=i;
while(l<=r){
m=(l+r)>>1;
if(judge(i,m)){
e=m;
l=m+1;
}else{
r=m-1;
}
}
ans+=(e-i+1);
}
printf("%I64d\n",ans);
}
return 0;
}
1012
树的删边游戏
从某一棵树上删除一条边,同时删去所有在删除边后不再与根相连的部分。双方轮流进行,无法再进行删除者判定为失败。
定理:
叶子节点的 SG 值为 0;
中间节点的 SG 值为它的所有子节点的 SG 值加 1 后的异或和。
对于建立圆的包含关系树,可以按半径从小到大排序,对于第一个大于并包含它的圆建边,然后break;
当然这是暴力的方法。交C++会TLE,交G++才会AC
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define LL __int64
#define N 100005
#define INF 1<<30
struct R{
int x,y,r;
}o[N];
bool cmp(R a,R b){
return a.r<b.r;
}
//判断包含关系,i被j包含
int judge(int i,int j){
if((o[i].x-o[j].x)*(o[i].x-o[j].x)+(o[i].y-o[j].y)*(o[i].y-o[j].y)<(o[i].r-o[j].r)*(o[i].r-o[j].r))
return 1;
return 0;
}
struct node{
int to,next;
}edge[N];
int head[N],k;
void init(){
k=1;
memset(head,0,sizeof(head));
}
void add(int u,int v){
edge[k].to=v;
edge[k].next=head[u];
head[u]=k++;
}
int dfs(int u){
int ret=0;
for(int i=head[u];i;i=edge[i].next){
ret^=(dfs(edge[i].to)+1);
}
return ret;
}
int main(){
int T;
int n;
scanf("%d",&T);
int ans,flag;
while(T--){
init();
ans=0;
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d%d%d",&o[i].x,&o[i].y,&o[i].r);
}
sort(o+1,o+n+1,cmp);
for(int i=1;i<=n-1;++i){
flag=0;
for(int j=i+1;j<=n;++j){
if(judge(i,j)){
add(j,i);
flag=1;
break;
}
}
if(!flag){
add(0,i);
}
}
add(0,n);
ans=dfs(0);
if(ans)printf("Alice\n");
else printf("Bob\n");
}
return 0;
}
(待续。。。)