这场AGC我竟然会四题,吓傻了
然后仔细一看发现BCD都是700pts的……果然我还是naive
E题好像还是不会= =
\(\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_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,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)\)
\(\bf Solution\):看起来不太新鲜的题……
莫比乌斯反演……
题目是有序对,转成无序对会比较好求,并且要把所有数存到一个桶 \(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; }