------------恢复内容开始------------
7-1 1A. 期望逆序对
对每一对按期望排序即可(猜出来的,很好证明)
#include <iostream> #include <map> #include <algorithm> #include <string.h> using namespace std; const int maxn=5e3+10; typedef long long ll; const int mod=998244353; ll len[maxn]; ll inv2; ll qp(ll a,ll b,ll mod) { ll ans=1; while(b) { if(b&1) ans=(ans*a)%mod; a=(a*a)%mod; b>>=1; } return ans; } ll J(ll l1,ll r1,ll l2,ll r2,int i,int j) { ll ans=0; if(r1>r2) { ans=(r1-r2)*(r2-l2+1)%mod; } if(l2<l1) { ans=(ans+(l1-l2)*(r1-l1+1))%mod; } // ans=(ans-max(0ll,l1-l2)*max(0ll,r1-r2)+mod)%mod; ll shang=min(r1,r2),xia=max(l1,l2); ll l=shang-xia+1; if(shang>xia) { ans=((ans+(l*l-l)%mod*inv2)%mod+mod)%mod; } return ((ans*len[i])%mod*len[j])%mod; } typedef pair<ll, ll> P; P a[maxn]; bool cmp(P a1,P a2) { if(a1.first+a1.second<a2.first+a2.second) return 1; else return 0; } ll n; int main() { inv2=qp(2, mod-2, mod); // cout<<(3*qp(8, mod-2, mod))%mod; scanf("%lld",&n); for(ll i=0;i<n;i++) scanf("%lld%lld",&a[i].first,&a[i].second); // cin>>a[i].first>>a[i].second; sort(a, a+n, cmp); for(int i=0;i<n;i++) { len[i]=qp(a[i].second-a[i].first+1, mod-2, mod); } ll ans=0; for(ll i=0;i<n;i++){ for(ll j=i+1;j<n;j++) { ll t=J(a[i].first, a[i].second, a[j].first, a[j].second,i,j); // cout<<a[i].first<<a[i].second<<a[j].first<<a[j].second<<" "<<t<<endl; ans=(ans+t)%mod; } } printf("%lld ",ans); }
7-2 1B. 密码学
签到
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; char s[1002][1002]; struct hh{ int x,y; }a[2001]; int n,m; bool daxie(char x){ if(x >= 'A' && x <= 'Z') return true; else return false; } char zhuan(char a,char b){ int x,y; if(daxie(a)) x = a - 'A' + 26; else x = a - 'a'; if(daxie(b)) y = b - 'A' + 26; else y = b - 'a'; int c = (y - x + 52) % 52; if(c <= 25) c += 'a'; else c += 'A' - 26; return (char)c; } void calc(int a,int b){ char s2[1003]; int cnt = 0,n1 = strlen(s[a]),m1 = strlen(s[b]); if(n1 < m1) while(cnt < m1){ for(int i = 0;i < n1;i ++) s2[i + cnt] = s[a][i]; cnt += n1; } else strcpy(s2,s[a]); for(int i = 0;i < m1;i ++) s[b][i] = zhuan(s2[i],s[b][i]); return; } void solve(){ cin >> n >> m; for(int i = 1;i <= m;i ++) scanf("%d%d",&a[i].x,&a[i].y); for(int i = 1;i <= n;i ++) scanf("%s",s[i]); for(int i = m;i >= 1;i --) calc(a[i].x,a[i].y); for(int i = 1;i <= n;i ++) printf("%s ",s[i]); return; } int main(){ solve(); return 0; }
7-3 1C. 染色图
首先应该是均摊颜色不难猜出,后来推公式有点烦,把n%i拆成n-n/i*i就行了,后来就分块就可以
#include<iostream> #include<cstdio> #include<algorithm> #include<set> #include<vector> #include<bitset> #include <string.h> #include <stack> using namespace std; #define ls rt<<1 #define rs rt<<1|1 typedef long long ll; const ll maxn = 998244353; const int mod=998244353; typedef pair<double, double> P; typedef long long ll; ll qp(ll a,ll b,ll mod) { ll ans=1; while(b) { if(b&1) ans=(ans*a)%mod; a=(a*a)%mod; b>>=1; } return ans; } ll J(ll L,ll R,ll k)//k/i { //n*k- xigema i*(k/i)x; ll ans=0; for(ll l=L,r=0;l<=R;l++) { if(k/l) r=min(R,k/(k/l)); else r=R; ans=(ans+(k/l)*(r-l+1))%mod; l=r; } return ans; } ll J2(ll L,ll R,ll k)//k/i*i { //n*k- xigema i*(k/i)x; ll ans=0; for(ll l=L,r=0;l<=R;l++) { if(k/l) r=min(R,k/(k/l)); else r=R; ans=((k/l)*(((r-l+1)*(l+r)/2)%mod)+ans)%mod; l=r; } return ans; } ll J3(ll L,ll R,ll k)//k/i*(k/i)*i { //n*k- xigema i*(k/i)x; ll ans=0; for(ll l=L,r=0;l<=R;l++) { if(k/l) r=min(R,k/(k/l)); else r=R; ans=(ans+((k/l)*(k/l)%mod)*(((r-l+1)*(l+r)/2)%mod))%mod; l=r; } return ans; } int main() { int T; cin>>T; while(T--) { ll l,r,k; cin>>k>>l>>r; ll ans2=(((k*k%mod-k)*(r-l+1)%mod-2*J(l, r, k)*k+J3(l, r, k)+J2(l, r, k))%mod+mod)%mod; cout<<(ans2*qp(2, mod-2, mod))%mod<<endl; } }
7-5 1E. 树与路径
这道题我觉得还是很神奇的,这题虽然题干和其他换根的题很像,但是其实是很难想的。现在从原始思路出发,要求出所有点为根时候的答案,必然要先求一个答案,然后求转移。转移的时候就非常巧妙了,通过列式子可以得出对于一条边的时候,你变化的答案,其实仅仅与这个点与顶点的距离有关,所以就是说是与当前深度与顶点的差值是有关系的。所以说,把当前深度和叠加的顶点深度开一个pair,算一下这个,转移有了,然后dfs求答案。这题换根题求转移的必然的,只是不太好找这个规律。
#include<iostream> #include<cstdio> #include<algorithm> #include<set> #include<vector> #include<bitset> #include <string.h> #include <stack> using namespace std; #define ls rt<<1 #define rs rt<<1|1 typedef long long ll; const int maxn = 3e5+1000; typedef pair<ll, ll> P; P b[maxn],flag[maxn]; vector<int> G[maxn]; int F[maxn][20]; int used[maxn],deep[maxn]; ll ans[maxn]; void J(ll x) { if(x<0||x>maxn) while(1); } void dfs(int x) { if(x<0||x>maxn) { while(1); } used[x]=1; for(int i=0;i<G[x].size();i++) { int v=G[x][i]; J(v); if(used[v]==0) { deep[v]=deep[x]+1; F[v][0]=x; for(int i=1;i<20;i++) { F[v][i]=F[F[v][i-1]][i-1]; } dfs(v); } } } int count2=0; void dfs2(int x) { count2++; if(count2>=maxn) while(1); if(x<0||x>maxn) { while(1); } used[x]=1; b[x].first=flag[x].first; b[x].second=flag[x].second; for(int i=0;i<G[x].size();i++) { int v=G[x][i]; J(v); if(used[v]==0){ dfs2(v); b[x].first+=b[v].first; b[x].second+=b[v].second; } } } void dfs3(int x,ll ans_t) { J(x); used[x]=1; ans_t+=b[x].first*deep[x]+b[x].second; ans[x]=ans_t; for(int i=0;i<G[x].size();i++) { int v=G[x][i]; J(v); if(used[v]==0) dfs3(v,ans_t); } } int lca(int t1,int t2) { if(deep[t1]<deep[t2]) swap(t1,t2); for(int i=19;i>=0;i--) { J(t1); J(t2); if(deep[t1]-(1<<i)>=deep[t2]) { t1=F[t1][i]; } } if(t1==t2) return t2; for(int i=19;i>=0;i--) { J(t1); J(t2); if(F[t1][i]!=F[t2][i]) { t1=F[t1][i]; t2=F[t2][i]; } } t1=F[t1][0]; J(t1); return t1; } int main() { deep[1]=1; int n,m; cin>>n>>m; if(n>299000) { while(1); } for(int i=0;i<n-1;i++) { int u,v; cin>>u>>v; J(u); J(v); G[u].push_back(v); G[v].push_back(u); } for(int i=0;i<20;i++) F[1][i]=1; memset(used, 0, sizeof used); dfs(1); for(int i=0;i<m;i++) { int t1,t2; cin>>t1>>t2; int f=lca(t1,t2); J(f); J(t1); J(t2); int l=-2*deep[f]+deep[t1]+deep[t2]; flag[t1].first+=-2; flag[t1].second+=2*deep[t1]-l-1+2; flag[t2].first+=-2; flag[t2].second+=2*deep[t2]-l-1+2; flag[f].first-=-4; flag[f].second-=2*deep[t1]-l-1+2; flag[f].second-=2*deep[t2]-l-1+2; ans[1]+=1ll*(deep[t1]-deep[f])*(deep[t2]-deep[f]); } memset(used, 0, sizeof used); dfs2(1); memset(used, 0, sizeof used); dfs3(1,ans[1]); for(int i=1;i<=n;i++){ cout<<ans[i]<<endl; } }