只做了前三题。。。。。
T1、选数
先把题目转化为求选n个数最大公约数为1,不用说了。
假定f[i]为选出n个数最大公约数为i的方案数。
由于题目中有条件H-L<=10^5,所以i<=10^5即可。
令L=(L-1)/i, R=H/i
f[i] = (R-L)^n - sigma f[a*i] - (R-L)
最后的R-L为减去全部选择一个数的方案数
答案为f[1]
PS:如果范围中有1,注意f[1]++,因为全部选1也是一种方案
另一种做法,可以直接用莫比乌斯反演,莫比乌斯函数求和可参见我的另一篇博文
这种做法比较卡时,PoPoQQQ大神正是用了种做法
http://blog.csdn.net/popoqqq/article/details/45078079
贴上我的代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn=100005, Mod=(1e9)+7;
int f[Maxn],L,R,n,k,i,j;
int qck(int a,int b){
int ret = 1;
for (;b>0;b>>=1){
if (b&1) ret=(long long)ret*a%Mod;
a=(long long)a*a%Mod;
}
return ret;
}
int main(){
//freopen("number.in","r",stdin);
//freopen("number.out","w",stdout);
scanf("%d%d%d%d",&n,&k,&L,&R);
L = (L-1)/k+1; R = R/k;
for (i=R-L;i>0;i--){
f[i] = (qck(R/i-(L-1)/i,n)-(R/i-(L-1)/i)+Mod)%Mod;
for (j=i+i;j<=R-L;j+=i)
f[i] = (f[i]-f[j]+Mod)%Mod;
}
if (L==1) f[1]++;
printf("%d\n",f[1]);
return 0;
}
T2、网络吞吐量
很经典的一道网络流题了,做法可以参见AHOI2006上学路线,不讲了
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define pb push_back
typedef long long LL;
const int INF=1e9;
LL flow[300000],Ds[505],Dt[505],minx,ans;
int a[1005],js[1005],c[1005];
int node[300000],next[300000];
int n,m,x,y,z,N,i,j,vj,tot,q[1005],l,r;
bool flag,v[505];
struct edge{ int x,w; };
vector <edge> e[505];
void Dijkstra(LL d[],int S){
for (i=1;i<=n;i++)
d[i]=INF, d[i]*=d[i];
memset(v,0,sizeof(v));
d[S] = 0;
for (i=1;i<n;i++){
LL minx = INF; minx*=minx;
for (j=1;j<=n;j++)
if (!v[j] && minx>d[j])
minx = d[j], vj = j;
v[vj] = 1;
int len = e[vj].size();
for (j=0;j<len;j++)
if (d[e[vj][j].x]>minx+e[vj][j].w)
d[e[vj][j].x]=minx+e[vj][j].w;
}
}
void add(int x,int y,LL z){
node[++tot]=y; next[tot]=a[x]; a[x]=tot; flow[tot]=z;
node[++tot]=x; next[tot]=a[y]; a[y]=tot; flow[tot]=0;
}
void init(){
memset(js,0,sizeof(js));
memset(c,10,sizeof(c));
for (q[l=r=1]=N,js[c[N]=0]=1;l<=r;l++)
for (i=a[q[l]];i;i=next[i])
if ((i&1) && c[node[i]]>c[q[l]]+1)
js[ c[ q[++r]=node[i] ]=c[q[l]]+1 ]++;
}
void sap(int x){
if (x==N){
ans += (LL)minx;
flag = 1;
return;
}
int minn = minx, e = N-1, i;
for (i=a[x];i;i=next[i])
if (flow[i]>0){
if (c[node[i]]+1==c[x]){
minx = min(minx, flow[i]);
sap(node[i]);
if (c[1]>=N) return;
if (flag) break; else minx = minn;
}
e = min(e,c[node[i]]);
}
if (flag) flow[i]-=minx, flow[i^1]+=minx;
else
{
if (--js[c[x]]==0) c[1]=N;
js[ c[x]=e+1 ]++;
}
}
int main(){
//freopen("network.in","r",stdin);
//freopen("network.out","w",stdout);
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
e[x].pb((edge){y,z});
e[y].pb((edge){x,z});
}
Dijkstra(Ds,1);
Dijkstra(Dt,n);
for (i=1,tot=1;i<=n;i++){
int len = e[i].size();
for (j=0;j<len;j++)
if (Ds[i]+Dt[e[i][j].x]+e[i][j].w==Ds[n])
add(i*2,e[i][j].x*2-1,INF);
}
for (i=1;i<=n;i++){
scanf("%d",&x);
if (i==1 || i==n)
add(i*2-1,i*2,(LL)INF*INF);
else add(i*2-1,i*2,x);
}
N = 2*n;
init();
while (c[1]<N) { flag=0;minx=INF;sap(1); }
printf("%lld\n",ans);
return 0;
}
T3、任务查询系统
似乎把这题做得复杂了,
说一说我的做法吧。
建两棵主席树,一棵插入顺序按左端点从小到大排序,一棵按右端点从小到大排序
每棵内层都都按权值插入节点,记录数量和所有插入节点的权值和。
查询的时候只要找到第一棵中左端点最大的小于他的位置和第二棵树中右端点最大的小于他的位置
两棵树做差分即可。
颓废无比。。。。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn=100005;
typedef long long LL;
LL lastans,sum2[Maxn*40];
int A,B,C,K,n,m,M,i,x,st,T[Maxn],S[Maxn];
int son[Maxn*40][2],sum1[Maxn*40],w[Maxn];
struct arr{ int s,e,p; }a[Maxn],b[Maxn];
bool cmp1(const arr &a,const arr &b)
{ return a.s<b.s; }
bool cmp2(const arr &a,const arr &b)
{ return a.e<b.e; }
void ins(int &q,int p,int l,int r,int pos){
q = ++st;
son[q][0] = son[p][0];
son[q][1] = son[p][1];
sum1[q] = sum1[p]+1;
sum2[q] = sum2[p]+(LL)w[pos];
if (l==r) return;
int mid = (l+r)>>1;
if (pos<=mid) ins(son[q][0],son[p][0],l,mid,pos);
else ins(son[q][1],son[p][1],mid+1,r,pos);
}
LL query(int p,int q,int l,int r,int s){
if (sum1[p]-sum1[q]+s<=K) return sum2[p]-sum2[q];
int mid=(l+r)>>1;
if (l==r) return (LL)(K-s)*w[l];
LL ret1 = query(son[p][0],son[q][0],l,mid,s), ret2 = 0;
s += sum1[son[p][0]]-sum1[son[q][0]];
if (s<K) ret2 = query(son[p][1],son[q][1],mid+1,r,s);
return ret1+ret2;
}
int get1(int x){
int l = 1, r = m, mid, ret=0;
while (l<=r){
mid = (l+r)>>1;
if (a[mid].s<=x) ret=mid, l=mid+1;
else r=mid-1;
}
return ret;
}
int get2(int x){
int l = 1, r = m, mid, ret=0;
while (l<=r){
mid = (l+r)>>1;
if (b[mid].e<=x) ret=mid, l=mid+1;
else r=mid-1;
}
return ret;
}
int main(){
//freopen("query.in","r",stdin);
//freopen("query.out","w",stdout);
scanf("%d%d",&m,&n);
for (i=1;i<=m;i++){
scanf("%d%d%d",&a[i].s,&a[i].e,&a[i].p);
b[i] = a[i]; w[i] = a[i].p;
}
sort(w+1,w+m+1);
M = unique(w+1,w+m+1)-w-1;
sort(a+1,a+m+1,cmp1);
sort(b+1,b+m+1,cmp2);
for (i=1;i<=m;i++){
a[i].p = lower_bound(w+1,w+M+1,a[i].p)-w;
ins(T[i],T[i-1],1,M,a[i].p);
}
for (i=1;i<=m;i++){
b[i].p = lower_bound(w+1,w+M+1,b[i].p)-w;
ins(S[i],S[i-1],1,M,b[i].p);
}
for (i=1,lastans=1;i<=n;i++){
scanf("%d%d%d%d",&x,&A,&B,&C);
K = ((LL)A*lastans+(LL)B)%(LL)C+1;
int t1 = get1(x), t2 = get2(x-1);
lastans = query(T[t1],S[t2],1,M,0);
printf("%lld\n",lastans);
}
return 0;
}