AtCoder Grand Contest 038

這場AGC我居然會四題,嚇傻了算法

而後仔細一看發現BCD都是700pts的……果真我仍是naivespa

E題好像仍是不會= =code

\(\bf A - 01 \ Matrix\)

\(\bf Solution\):直接貼代碼(由於太淺顯了0_0)排序

#include<bits/stdc++.h>
#define ll long long
#define fr(i,x,y) for(int i=(x);i<=(y);i++)
#define rf(i,x,y) for(int i=(x);i>=(y);i--)
#define frl(i,x,y) for(int i=(x);i<(y);i++)
using namespace std;
const int N=2002;
int n,m,A,B;

int main(){
    cin>>n>>m>>A>>B;
    fr(i,1,n){
        fr(j,1,m)
         printf("%d",(i<=B)^(j<=A));
        puts("");
    }
    return 0;
}

\(\bf B- Sorting \ a \ Segment\)

\(\bf Description\):給你一個長度爲 \(n\) 的排列,一次操做能夠選擇連續 \(k\) 個進行排序,問一次操做後有多少種可能排列。隊列

\(\bf Solution\):首先顯然一段區間遞增的話排序後不變,因此先把這樣的區間踢掉。而後咱們考慮選擇 \([i,i+k-1]\)\([i+1,i+k]\) 這兩個區間操做後,若是得到的排列是同樣的話,那麼顯然 \(P_i\)\([i,i+k-1]\) 的最小值,\(P_{i+k}\)\([i+1,i+k]\) 的最大值,用單調隊列預處理滑動窗口最值就行了……固然想寫線段樹或者ST表什麼的也闊以0_0ip

#include<bits/stdc++.h>
#define ll long long
#define fr(i,x,y) for(int i=(x);i<=(y);i++)
#define rf(i,x,y) for(int i=(x);i>=(y);i--)
#define frl(i,x,y) for(int i=(x);i<(y);i++)
using namespace std;
const int N=200002;
int n,K,a[N];
int h[N],t,w;
int mn[N],mx[N];

void read(int &x){
    char ch=getchar();x=0;
    for(;ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
}

void push(int x,bool (*cmp)(int,int)){
    while(w>=t&&cmp(a[h[w]],a[x])) w--;
    h[++w]=x;
}

int find(int x){
    while(h[t]<=x-K) t++;
    return a[h[t]];
}

bool big(int x,int y){ return x>y; }
bool small(int x,int y){ return x<y; }

void init(){
    t=1;w=0;
    fr(i,1,n){
        push(i,big);
        mn[i]=find(i);
    }
    t=1;w=0;
    fr(i,1,n){
        push(i,small);
        mx[i]=find(i);
    }
}

int main(){
    read(n);read(K);
    fr(i,1,n) read(a[i]);
    init();
    int flag=0;
    fr(i,2,K) if (a[i-1]>a[i]) flag++;
    int bo=0,ans=0;
    fr(i,K,n){
        if (flag==0) bo=1;
         else{
            if (i==K||a[i-K]!=mn[i-1]||a[i]!=mx[i]) ans++;
         }
        flag-=a[i-K+1]>a[i-K+2];
        flag+=a[i]>a[i+1];
    }
    cout<<ans+bo<<endl;
    return 0;
}

\(\bf C-LCMs\)

\(\bf Description\):求 \(\sum_{i=1}^{N-1} \sum_{j=i+1}^{N} lcm(A_i,A_j)\)ci

\(\bf Solution\):看起來不太新鮮的題……get

莫比烏斯反演……it

題目是有序對,轉成無序對會比較好求,而且要把全部數存到一個桶 \(s\)

\(g(x)=(\sum_{i=1}^{M/x} s_{xi} \cdot xi)^2\)\(M\) 是值域)

而後給 \(g\) 反演一下變成 \(f\) ,這裏用的是第二種莫比烏斯反演:若\(g(n)=\sum_{n|d}f(d)\),則\(f(n)=\sum_{n|d}\mu(d/n)g(d)\)

而後答案顯然是 \(\sum_{i=1}^M \frac{f(i)}{i}\)

啊感性理解

#include<bits/stdc++.h>
#define ll long long
#define fr(i,x,y) for(int i=(x);i<=(y);i++)
#define rf(i,x,y) for(int i=(x);i>=(y);i--)
#define frl(i,x,y) for(int i=(x);i<(y);i++)
using namespace std;
const int N=200002;
const int M=1000002;
const int p=998244353;
const int inv2=(p+1)/2;
int n,a[N],s[M];
int mu[M];
ll sum[M],f[M];

void read(int &x){
    char ch=getchar();x=0;
    for(;ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
}

void Add(ll &x,ll y){
    x+=y;
    while(x>=p) x-=p;
    while(x<0) x+=p;
}

int b[M],pri[M],L;
void init(){
    mu[1]=1;
    frl(i,2,M){
        if (!b[i]) pri[++L]=i,mu[i]=-1;
        for(int j=1;j<=L&&i*pri[j]<M;j++){
            b[i*pri[j]]=1;
            if (i%pri[j]==0) break;
             else mu[i*pri[j]]=-mu[i];
        }
    }
}

ll qpow(ll sum,ll n){
    ll ans=1;
    for(;n;n>>=1,sum=sum*sum%p) if (n&1) ans=ans*sum%p;
    return ans;
}

int main(){
    read(n);
    fr(i,1,n) read(a[i]),s[a[i]]++;
    init();
    frl(i,1,M){
        for(int j=i;j<M;j+=i)
         Add(sum[i],1LL*s[j]*j);
        sum[i]=sum[i]*sum[i]%p;
    }
    frl(i,1,M){
        for(int j=i;j<M;j+=i)
         Add(f[i],sum[j]*mu[j/i]);
    }
    ll ans=0;
    frl(i,1,M){
        if (f[i]) Add(ans,f[i]*qpow(i,p-2)%p);
    }
    fr(i,1,n) Add(ans,-a[i]);
    cout<<ans*inv2%p<<endl;
    return 0;
}

\(\bf D-Unique \ Path\)

\(\bf Description\):有一張 \(n\) 個點 \(m\) 條邊的聯通圖,告訴你某些點對之間只有一條簡單路徑,某些有兩條,問這樣的圖是否存在。

\(\bf Solution\):首先發現一張圖裏,除了那些看起來在一棵樹上的點之間只有一條路,其餘都有多條。。這啓發咱們對於全部 \(C_i=0\) 的邊維護一下連通性,在一個聯通塊裏就表示在一棵看起來像樹的東西上面(可能有些結點上會掛不少圈圈)。若是有 \(C_i=1\) 的邊鏈接的兩個點在同一個聯通塊裏那顯然是不行的。而後假如如今有 \(cnt\) 個聯通塊,咱們發現最多還能夠連 \(cnt(cnt-1)/2\) 條邊,因此若是邊數多與 \(n-cnt+cnt(cnt-1)/2\) 那確定不行。而後還有就是若是隻有一或倆聯通塊可是有 \(C_i=1\) 的邊那也不行。若是有 \(C_i=1\) 的邊那就起碼有 \(n\) 條邊,因此若是隻有 \(n-1\) 條也不行。。

細節好多,我爆了5發才過= =都要懷疑是否是又胡假算法惹0_0

#include<bits/stdc++.h>
#define ll long long
#define fr(i,x,y) for(int i=(x);i<=(y);i++)
#define rf(i,x,y) for(int i=(x);i>=(y);i--)
#define frl(i,x,y) for(int i=(x);i<(y);i++)
using namespace std;
const int N=200002;
int n,Q;
ll m;
struct data{
    int x,y,w;
    bool operator < (const data &q)const{ return w<q.w; }
}a[N];
int f[N];

template<class T> void read(T &x){
    char ch=getchar();x=0;
    for(;ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
}

int gf(int x){ return f[x]==x?x:f[x]=gf(f[x]); }

int main(){
    read(n);read(m);read(Q);
    fr(i,1,Q) read(a[i].x),read(a[i].y),read(a[i].w);
    fr(i,1,Q) a[i].x++,a[i].y++;
    sort(a+1,a+1+Q);
    fr(i,1,n) f[i]=i;
    int flag=0;
    fr(i,1,Q){
        if (a[i].w){
            flag=i;
            break;
        }
        int x=a[i].x,y=a[i].y;
        f[gf(x)]=gf(y);
    }
    if (flag) fr(i,flag,Q) if (gf(a[i].x)==gf(a[i].y)) return puts("No"),0;
    int cnt=0;
    fr(i,1,n) if (gf(i)==i) cnt++;
    if (!flag){
        if (m>1LL*cnt*(cnt-1)/2+n-cnt) puts("No");
         else puts("Yes");
    } else{
        if (cnt<=2||m<n) puts("No");
         else if (m>1LL*cnt*(cnt-1)/2+n-cnt) puts("No");
          else puts("Yes");
    }
    return 0;
}
相關文章
相關標籤/搜索