CCPC-Wannafly 自闭day1

 

B:

简单的模拟,WA是因为误以为m最多是n的2倍,其实可以是好多倍,只要n不断循环直到不小于m即可。

#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\n",s[i]);
    return;
}

int main(){
    solve();
    return 0;
}
View Code

 

C:

好题。

让边数最大,显然是让每两个不同颜色的点之间连一条边。

对于n个点,m种颜色。

答案为:$C_{n}^{2} - \sum_{i = 1}^{m} C_{a_i}^{2}$

其中$a_1,a_2...a_m$表示每种颜色点的个数。

考虑如果使这个公式取值最大,则将n均匀地分给m种颜色。

对于每个m:

    $C_{n}^{2}-\left (n\ mod\ m \right )*C_{\lceil{\frac{n}{m}}\rceil}^{2}-\left (m-n\ mod \ m \right )*C_{\lfloor{\frac{n}{m}}\rfloor}^{2}$

$= C_{n}^{2}-\left (n-{\lfloor{\frac{n}{m}}\rfloor * m}\right )*C_{\lceil{\frac{n}{m}}\rceil}^{2}-\left (m-n+{\lfloor{\frac{n}{m}}\rfloor}*m\right )*C_{\lfloor{\frac{n}{m}}\rfloor}^{2}$

$= C_{n}^{2}-n * {C_{\lceil{\frac{n}{m}} \rceil} ^ 2} + n * {C_{\lfloor{\frac{n}{m}} \rfloor} ^ 2} + m*\left [ {\lfloor{\frac{n}{m}}\rfloor} *\left ( {C_{\lceil{\frac{n}{m}} \rceil} ^ 2} - C_{\lfloor{\frac{n}{m}} \rfloor} ^ 2\right ) - C_{\lfloor{\frac{n}{m}} \rfloor} ^ 2\right ]$

最后可以发现前面的公式只与$C_{\lceil{\frac{n}{m}} \rceil} ^ 2$,$n$,$C_{\lfloor{\frac{n}{m}} \rfloor} ^ 2$有关,后面m所乘的数也是只与$C_{\lceil{\frac{n}{m}} \rceil} ^ 2$,$n$,$C_{\lfloor{\frac{n}{m}} \rfloor} ^ 2$有关,可以用除法分块的知识处理$C_{\lceil{\frac{n}{m}} \rceil} ^ 2$,$C_{\lfloor{\frac{n}{m}} \rfloor} ^ 2$。因此对于每一个块 $m\in (l,r)$ 包含(r - l + 1)个$C_{n}^{2}-n * {C_{\lceil{\frac{n}{m}} \rceil} ^ 2} + n * {C_{\lfloor{\frac{n}{m}} \rfloor} ^ 2} $ 以及 (l + r)(r - l + 1) 个 $\left [ {\lfloor{\frac{n}{m}}\rfloor} *\left ( {C_{\lceil{\frac{n}{m}} \rceil} ^ 2} - C_{\lfloor{\frac{n}{m}} \rfloor} ^ 2\right ) - C_{\lfloor{\frac{n}{m}} \rfloor} ^ 2\right ]$。

知识点:

1、除法分块,(1,n)中有相同${\lfloor{\frac{n}{m}} \rfloor}$的最大值为$\frac{n}{{\lfloor{\frac{n}{m} }\rfloor}}$。

2、${\lceil{\frac{n}{m}} \rceil} = {\lfloor{\frac{n - 1}{m}} \rfloor + 1} $

时间复杂度$O\left (T \sqrt{n} \right )$

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll MAXN = 3e6 + 66;
const ll mod = 998244353;
ll T,n,l,r;

ll f(ll a,ll b){
    return (a + b) * (b - a + 1) / 2 % mod;
}
ll C(ll x){
    return x * (x - 1) / 2 % mod;
}
ll calc(ll n,ll m){
    return (C((n - 1) / m + 1)  - C(n / m) + mod) % mod;
}

void solve(){
    ll ans = 0;
    scanf("%lld%lld%lld",&n,&l,&r);
    for(int i = l,t;i <= r && i <= n;i = t + 1){
        t = min(n / (n / i),r);
        ans = (ans + (t - i + 1) * (C(n) % mod - n * calc(n,i) % mod + mod) % mod) % mod;
        ans = (ans + f(i,t) % mod * ((n / i) * calc(n,i) - C(n / i) + mod) % mod) % mod;
    }
    printf("%lld\n",ans % mod);
}

int main(){
    cin >> T;
    while(T --)
    solve();
    return 0;
}
View Code
posted @ 2020-01-17 17:05  cgold  阅读(166)  评论(0)    收藏  举报