A
題目描述
給個n,求1到n的所有數的約數個數的和~
輸入描述:
第一行一個正整數n
輸出描述:
輸出一個整數,表示答案
輸入
3
輸出
5
說明
樣例解釋: 1有1個約數1 2有2個約數1,2 3有2個約數1,3
備註:
n <= 100000000
#include<stdio.h>
int deal(int n)
{
int ans=0;
for(int i=1;i<=n;i++)
ans+=n/i;
return ans;
}
int main()
{
int n;
//freopen("in.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
printf("%d\n",deal(n));
return 0;
}
B
題目描述
每次給個區間[l,r],查詢把這個區間內所有儲物點的東西運到另外一個儲物點的代價是多少?
比如儲物點i有x個東西,要運到儲物點j,代價爲x * dist( i , j )
dist就是儲物點間的距離。
輸入描述:
第一行兩個數表示n,m
第二行n-1個數,第i個數表示第i個儲物點與第i+1個儲物點的距離ai
第三行n個數,表示每個儲物點的東西個數bi
之後m行每行三個數x l r
輸出描述:
對於每個詢問輸出一個數表示答案 答案對1000000007取模
輸入
5 5 2 3 4 5 1 2 3 4 5 1 1 5 3 1 5 2 3 3 3 3 3 1 5 5
輸出
125 72 9 0 70
備註:
對於100%的數據n,m <= 200000 , 0 <= ai,bi <= 2000000000
思路:
計算所有點到點1的距離以及前綴和,然後根據關係計算得到答案即可
另一種思路:計算前面所有點到 i 的權值和,但是不知道爲什麼一直錯,找不到原因了
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define LL long long
#define mod 1000000007
int n,m;
LL a[MAXN],b[MAXN],s[MAXN];
void init(){
for(int i=2;i<=n;i++)
scanf("%lld",&a[i]),a[i]=(a[i]+a[i-1])%mod;
for(int i=1;i<=n;i++)
scanf("%lld",&b[i]),s[i]=(s[i-1]+a[i]*b[i])%mod,b[i]=(b[i]+b[i-1])%mod;
}
LL get_left(int l,int r,int x){
return a[x]*(b[r]-b[l-1])-(s[r]-s[l-1]);
}
LL get_right(int l,int r,int x){
return s[r]-s[l-1]-a[x]*(b[r]-b[l-1]);
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
while(m--)
{
int x,l,r;
scanf("%d%d%d",&x,&l,&r);
LL ans=0;
if(x>=r) ans=get_left(l,r,x);
else if(x<=l) ans=get_right(l,r,x);
else ans=get_left(l,x,x)+get_right(x,r,x);
printf("%lld\n",(ans%mod+mod)%mod);
}
}
return 0;
}
D
題目描述
給你一個 n 個點,m 條邊的無向圖,求至少要在這個的基礎上加多少條無向邊使得任意兩個點可達~
輸入描述:
第一行兩個正整數 n 和 m 。 接下來的m行中,每行兩個正整數 i 、 j ,表示點i與點j之間有一條無向道路。
輸出描述:
輸出一個整數,表示答案
輸入
4 2 1 2 3 4
輸出
1
備註:
對於100%的數據,有n,m<=100000。
利用並查理求得連通塊有ans個,則輸出 ans-1即可
也可以利用dfs,bfs求得
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAXN 100005
int father[MAXN],visit[MAXN];
int find_it(int x){
int tempx=x,t;
while(tempx!=father[tempx])
tempx=father[tempx];
while(father[x]!=x){
t=father[x];
father[x]=tempx;
x=t;
}
return tempx;
}
void unite(int num1,int num2){
int tx=find_it(num1);
int ty=find_it(num2);
if(tx!=ty)
father[tx]=ty;
}
int main()
{
int n,m,a,b;
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<=n;i++)
father[i]=i;
for(int i=0;i<m;i++){
scanf("%d%d",&a,&b);
unite(a,b);
}
int ans=0;
for(int i=1;i<=n;i++)
if(father[i]==i)
ans++;
printf("%d\n",ans-1);
}
return 0;
}
E
題目描述
給出一個集合和一個數m。
集合裏面有n個質數。
請你求出從 1 到 m 的所有數中,至少能被集合中的一個數整除的數的個數。
輸入描述:
第一行兩個正整數 n 和 m 。 第二行n個正整數,分別爲集合中的質數。
輸出描述:
輸出一個整數,表示符合要求的正整數的個數。
輸入
3 37 5 7 13
輸出
13
備註:
對於100%的數據,有n<=20,m爲有符號64位正整數,集合內質數<=1000000000
容斥原理處理一下
注意這裏n個數都是質數,我們可以直接兩個數相乘得到最大公約數,如果不能保證是質數,則要求得最大公約數
因爲18/6 + 18/9 - 18/lcm(6,9)答案纔是正確的
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define LL long long
LL a[100];
LL n,m,ans;
LL gcd(LL a,LL b)
{
return b?gcd(b,a%b):a;
}
LL lcm(LL a,LL b)
{
return a*b/gcd(a,b);
}
void dfs(int now,LL num,int sym)
{
if(num) ans+=m/num*sym;
for(int i=now+1;i<=n;i++)
dfs(i,lcm(num,a[i]),-1*sym);
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%lld%lld",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
ans=0;
for(int i=1;i<=n;i++)
dfs(i,a[i],1);
printf("%lld\n",ans);
}
return 0;
}