https://www.nowcoder.com/acm/contest/39#question
收穫:學習了容斥原理(一語成讖,當亞洲賽開始前我告訴自己,如果現在不努力學習算法,以後肯定還要在學習,但是那個時候學習的時候就有一點悲傷的感覺了qwq),和a,b的腦洞。a是數學腦洞,b是前綴和,也有線段樹。(然而不加掛都過不去)
不足:線段樹代碼明顯寫的不好,碼力還是不行。慢慢提高吧qwq
A :給定n,求1-n中每個數的 約數和的和。
思路:開始矇蔽,後來發現枚舉約數1-n,除一下就行了(商就是n內有多少個)
#include <bits/stdc++.h>
using namespace std;
/*
*/
int main()
{ int m;
scanf("%d",&m);
int sum=0;
for(int i=1;i<=m;i++){
sum+=m/i;
}
printf("%d\n",sum);
return 0;
}
B 一個數軸,每一個儲物點會有一些東西,同時它們之間存在距離。
每次給個區間[l,r],查詢把這個區間內所有儲物點的東西運到另外一個儲物點的代價是多少?
比如儲物點i有x個東西,要運到儲物點j,代價爲x * dist( i , j )
dist就是儲物點間的距離。
思路:用前綴和維護一下,維護距離,數量和 距離*數量的前綴和。
分兩種情況。當要移動的位置x在區間左邊。 和再區間右邊。
(具體可以這樣理解,物品從區間移動到最左邊,然後再移動到x,當x區間左邊時,)
線段樹也是這樣
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define MN 200010
int n,m,ll,rr,dis[MN],sum1[MN],sum2[MN],a[MN],x,p=1e9+7;
int work(int l,int r,int k,int x)
{
if(l>r) return 0;
return
k==-1?((sum1[r]-sum1[l-1]+p)%p-((LL)dis[x]*((sum2[r]-sum2[l-1]+p)%p))%p+p)%p
:(((LL)dis[x]*((sum2[r]-sum2[l-1]+p)%p))%p-(sum1[r]-sum1[l-1]+p)%p+p)%p;
}
int main()
{
// freopen("sample3.in","r",stdin);
// freopen("a.txt","w",stdout);
cin>>n>>m;for(int i=2,_;i<=n;i++)
cin>>_,dis[i]=(dis[i-1]+_)%p;//sum1[i]=(sum1[i-1]+dis[i])%p;
for(int i=1;i<=n;i++)
cin>>a[i],a[i]%=p,sum2[i]=(sum2[i-1]+a[i])%p,sum1[i]=(sum1[i-1]+((LL)a[i]*dis[i])%p)%p;
// for(int i=1;i<=n;i++) if(sum2[i]<0||dis[i]<0||a[i]<0) cout<<" swdwd";
while(m--)
{
cin>>x>>ll>>rr;
if(x>rr) cout<<work(ll,rr,1,x)<<endl;
else if(x<ll) cout<<work(ll,rr,-1,x)<<endl;
else cout<<(work(ll,x-1,1,x)+work(x+1,rr,-1,x))%p<<endl;
}
return 0;
}
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
using namespace std;
const int maxn = 200005,P = 1e9+7;
inline LL read(){
LL out = 0,flag = 1;char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1;c = getchar();}
while (c >= 48 &&c <= 57) {out = out * 10 + c - 48;c = getchar();}
return out * flag;
}
LL n,m,Sum[maxn],A[maxn];
void init(){
n = read();
m = read();
Sum[1] = 0;
for (int i = 2; i <= n; i++)
Sum[i] = (Sum[i - 1] + read()) % P;
for (int i = 1; i <= n; i++)
A[i] = read() % P;
}
LL V[2][4 * maxn],sum[4 * maxn];
void build(int u,int l,int r){
if (l == r){
V[0][u] = V[1][u] = 0;
sum[u] = A[l];
}else {
int mid = (l + r) >> 1;
build(u << 1,l,mid);
build(u << 1 | 1,mid + 1,r);
V[0][u] = (V[0][u<<1] + V[0][u<<1|1] + sum[u<<1|1] * (Sum[mid + 1] - Sum[l]) % P) % P;
V[1][u] = (V[1][u<<1] + V[1][u<<1|1] + sum[u<<1] * (Sum[r] - Sum[mid]) % P) % P;
sum[u] = (sum[u << 1] + sum[u << 1 | 1]) % P;
}
}
struct node{
LL v,sum,l,r;
};
int L,R;
node Query(int u,int l,int r,int p){
if (l >= L && r <= R){
return (node){V[p][u],sum[u],l,r};
}else {
int mid = (l + r) >> 1;
if (mid >= R) return Query(u<<1,l,mid,p);
else if (mid < L) return Query(u<<1|1,mid + 1,r,p);
else {
node a = Query(u<<1,l,mid,p),b = Query(u<<1|1,mid + 1,r,p);
if (p == 0){
return (node){(a.v + b.v + b.sum * (Sum[mid + 1] - Sum[a.l]) % P) % P,(a.sum + b.sum) % P,a.l,b.r};
}else {
return (node){(a.v + b.v + a.sum * (Sum[b.r] - Sum[mid]) % P) % P,(a.sum + b.sum) % P,a.l,b.r};
}
}
}
}
void solve(){
LL x,l,r,ans;
node u;
while (m--){
x = read();
l = read();
r = read();
if (x <= l){
L = l; R = r;
u = Query(1,1,n,0);
printf("%lld\n",((u.v + u.sum * (Sum[l] - Sum[x]) % P) % P + P) % P);
}else if (x >= r){
L = l; R = r;
u = Query(1,1,n,1);
printf("%lld\n",((u.v + u.sum * (Sum[x] - Sum[r]) % P) % P + P) % P);
}else {
L = x; R = r;
u = Query(1,1,n,0);
ans = u.v;
L = l; R = x;
u = Query(1,1,n,1);
ans =((ans + u.v) % P + P) % P;
printf("%lld\n",ans);
}
}
}
int main(){
init();
build(1,1,n);
solve();
return 0;
}
D直接寫就行,這個比較水qwq,求聯通分量之後,-1就行。(特判爲1)
include <bits/stdc++.h>
using namespace std;
/* 水題?分塊?
*/
const int maxn=1e5+200;
bool vis[maxn];
int m,n;
vector<int>g[maxn];
void dfs(int u){
for(int i=0;i<g[u].size();i++){
int to=g[u][i];
if(!vis[to]){
vis[to]=true;
dfs(to);
}
}
}
int main()
{ int a,b;
scanf("%d%d",&m,&n);
memset(vis,false,sizeof(vis));
for(int i=0;i<n;i++){
scanf("%d%d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
}
int sum=0;
for(int i=1;i<=m;i++){
if(!vis[i]){
vis[i]=true;
dfs(i);
sum++;
}
}
printf("%d\n",sum-1);
return 0;
}
E :容斥。求出n的全排列,其實我感覺這個寫法很模板qwq。
#include <bits/stdc++.h>
using namespace std;
/* 容斥原理。
現在學這種東西,心裏是很傷心的,
傷心自己以前沒有好好看數學的東西qwq
主要是比賽前太害怕搜索會出事了
*/
typedef long long ll;
const int maxn=25;
int va[maxn];
int n;
ll m;
ll solve(int s,ll num){
ll sumall=0;
for(int i=0;i<(1<<s);i++){
int tim=0;
ll sum=1;
for(int j=0;j<s;j++){
if(i&(1<<j)){
sum*=va[j];
tim++;
}
}
if(tim%2){
sumall+=num/sum;
}
else if(tim!=0){
sumall-=num/sum;
}
//cout<<sumall<<" "<<num<<" "<<sum<<endl;
}
return sumall;
}
int main()
{ int a;
ll b;
while(~scanf("%d%lld",&a,&b)){
for(int i=0;i<a;i++){
scanf("%d",&va[i]);
}
printf("%d\n",solve(a,b));
}
return 0;
}