2020 wannafly camp day1

------------恢复内容开始------------

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;
    }
    
}
原文地址:https://www.cnblogs.com/King-of-Dark/p/12236750.html