Jeanny
寂兮,寥兮,独立不改,周行而不殆

T3 回文

!!!这是一道极好的枚举题目

小 C 有一个长度为 \(n\)由小写字母构成的字符串 \(S\)

小 C 现在可以对 \(S\) 做一些变换,但变换是需要代价的,将字母 \(c_1\) 变成 \(c_2(c_1\ne c_2)\) 的代价为 \(v_{c_2}\),其中 \(v\) 是一个长度为 \(26\) 的数组。(为了方便理解,规定字母 a 对应数字 \(1\),字母 b 对应数字 \(2\),以此类推)

小 C 在做上述变换前可以先选择两个位置并交换两个位置上的字母(该操作最多做一次且代价为 \(0\)),然后再将字母随意变换。

小 C 想要知道将 \(S\) 变成回文串的最小代价,保证 \(2|n\)

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define ll long long
#define dbug(x) (void)(cerr << #x << " = " << x << endl)

ll n, v[30];
string s;
ll minn = INT_MAX;
ll cost[27][27];
ll freq[27][27]; // 添加频率数组记录字符对出现次数

inline ll oside(ll x) {
    return n - x + 1;
}

inline ll f(string s){
    ll ans = 0;
    for (ll i = 1; i <= n / 2; i++) {
        if (s[i] != s[oside(i)]){
            int c1 = s[i] - 'a' + 1;
            int c2 = s[oside(i)] - 'a' + 1;
            ll current_cost = min({2 * minn, v[c1], v[c2]});
            ans += current_cost; 
            int minC = min(c1, c2);// 标准化为有序对,确保第一个索引不大于第二个索引
            int maxC = max(c1, c2);
            freq[minC][maxC]++; // 记录出现次数
        }
    }
    return ans;
}
int cs(int x, int y){
    if(x == y) return 0;
    return min({2*minn, v[y], v[x]});
}

int main() {
	freopen("palindrome.in", "r", stdin);
	freopen("palindrome.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> n;
    for (ll i = 1; i <= 26; i++) {
        cin >> v[i];
        minn = min(minn, v[i]);
        for(ll j = 1; j <= 26; j++){
            freq[i][j] = 0; // 初始化频率数组
        }
    }
    cin >> s;
    s = " " + s;
    ll ans, sum, temp;
    temp = ans = sum = f(s);

    
    if (sum == 0) {// 如果已经是回文,直接输出0
        cout << 0 << endl; return 0;
    }

    // 26^4枚举交换可能性,ac一对,bd一对,然后ab进行交换 
    for(ll a = 1; a <= 26; a++){
        for(ll b = a+1; b <= 26; b++){
            for(ll c = 1; c <= 26; c++){
                for(ll d = 1; d <= 26; d++){
                    int min_ac = min(a, c);// 标准化字符对为有序对
                    int max_ac = max(a, c);
                    int min_bd = min(b, d);
                    int max_bd = max(b, d);
                    
                    if (freq[min_ac][max_ac] == 0 || freq[min_bd][max_bd] == 0) continue;// 检查字符对是否存在
                    
                    if (min_ac == min_bd && max_ac == max_bd) {//x:本质上zhiyou 是同一对,比如a   ....  b  ,a要和b交换,这是不行的 
                        if (freq[min_ac][max_ac] == 1) continue;
                    }    
                    // 计算旧代价和新代价
                    ll old_cost = cs(a, c) + cs(b, d);
                    ll new_cost = cs(b, c) + cs(a, d); //如果像 x那样交换,则c,c一对,a,a一对,所以很多测试点过不去 
                    ans = min(ans, temp - old_cost + new_cost);
                    
                }
            }
        }
    }
    
    cout << ans << endl;
    return 0;
}

T4 CodeForces 1670F Jee, You See?

小 C 喜欢序列,某一天他随手写下了一个长度为 \(n\) 的序列 \(A\),其中 \(\forall 1\le i\le n\)\(A_i \ge 0\)

可惜小 C 不小心弄丢了这个序列,但是他保存下了序列 \(A\) 的一些特征。

  • \(l\le \sum_{i=1}^n A_i\le r\)
  • \(\bigoplus_{i=1}^n A_i=z\)

其中 \(\bigoplus\) 为二进制下的异或运算符号,\(l,r,z\) 都为常数。

现在小 C 想要知道多少种可能的序列 \(A\) 满足他所给出的特征,由于答案可能很大,你只需要告诉小 C 答案对 \(10^9+7\) 取模后的值。

  • 对于 \(20\%\) 的数据,保证 \(r\le 30\)
  • 对于 \(40\%\) 的数据,保证 \(n\le 20\)\(r\le 500\)
  • 对于另 \(20\%\) 的数据,保证 \(n=2\)
  • 对于另 \(20\%\) 的数据,保证 \(n\le 50\)
  • 对于 \(100\%\) 的数据,保证 \(1\le n\le 10^{3}\)\(1\le l\le r\le 10^{18}\)\(1\le z\le 10^{18}\)

1.40分dp
状态:前i个数,枚举每个数,异或之后的值,总和。答案dp[n][s+x][p^x] += dp[n-1][s][p];
2.满分处理,非常的数位dp。异或的操作一般都是拆位,通过枚举每一位,如果z的这意味是1,则需要从n个数中选择奇数个当前这一位是1的数字。

dfs中当前这一位,如果为1,则枚举选择奇数个数字是几。
那么如何处理是否比r大?传一个变量b。如果比r的当前位小,则前面位都大也可以,比如
r的每一位是11011,前面的位枚举出来是xxx00,如果当前倒数第三位是1,1>r的这一位,成为xx100,则它一定比r大。反之,如果比r这一位小,即使前面都大,则也比r小。如果相等,则原来大还是大,原来小还是小。

int dfs(int pos,int c,int b) { //第pos位, 进位,是否比当前数字大了
	if(pos>len) {
		if(!c&&!b) return 1;
		return 0;
	}
	if(~dp[pos][c][b]) return dp[pos][c][b];
	int ret=0;
	for(int i=0; i<=n; i++) { //枚举有几个数当前pos位是1
		if((i&1)!=zz[pos]) continue;//与z的第pos位奇偶相同
		int now=(i+c)&1; //当前pos位是几(0或者1)
		bool bb=(now<num[pos])?0:(now==num[pos])?b:1; //x的pos位是num[pos] 
		ret=(ret+dfs(pos+1,(i+c)/2ll,bb)*C[n][i]);
	}
	return dp[pos][c][b]=ret;
}
posted on 2025-09-06 17:07  Jeanny  阅读(19)  评论(0)    收藏  举报