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; }
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; }