您的位置:首页 > 其它

HDU 4407 Sum

2016-03-30 20:52 381 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4407



题意:有n个数,分别为1到n。

每次有两个操作:

1、求第x个数到第y个数范围内所有与p互质的数之和。

2、将第x个数的值改为c。



思路:由于操作小于1000,我们可以先记录所有的2操作(map),先用容斥查询一下,然后再去调整答案。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;

#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)

#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod %100000007

int T,n,m;
//int a[1009]; // pos
//int b[1009]; // value
int num;
map<int,int> a;

int gcd(int a,int b)
{
return (a%b==0)?b:gcd(b,a%b);
}

LL query(int n,int p)
{
int f[20];
int m = 0;
LL ans = n;
ans*=(n+1);
ans>>=1;

for(int i = 2; i*i <= p; i++)
if ( p % i == 0 )
{
f[m++] = i;
while( p % i == 0 ) p /= i;
}
if ( p > 1 ) f[m++] = p;
int uplim = 1<<m;
rep(i,1,uplim-1)
{
int cnt = 1;
int t = 0;
rep(j,0,m-1)
if ( i & (1<<j) )
{
cnt*=f[j];
t++;
}
int k = n/cnt;
if ( t & 1 ) ans -= (LL)cnt*(k+1)*k/2;
else ans += (LL)cnt*(k+1)*k/2;
}
return ans;
}

LL update(int x,int y,int p)
{
LL ans = 0;
map<int,int> ::iterator it = a.begin();
for( ; it != a.end() ; it++)
if ( (*it).first >=x && (*it).first <= y )
{
if ( gcd( (*it).first , p )==1 ) ans+=(*it).first;
if ( gcd( (*it).second , p )==1 ) ans-=(*it).second;
}
return ans;
}

int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
int type,x,y,p;
//num = 0;
a.clear();
rep(i,1,m)
{
scanf("%d",&type);
if ( type == 2 )
{
scanf("%d %d",&x,&p);
//num++;
a[x] = p;
//b[num] = p;
}
else
{
scanf("%d%d%d",&x,&y,&p);
LL ans = query(y,p) - query(x-1,p);
ans-=update(x,y,p);
printf("%I64d\n",ans);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: