链接:https://codeforces.com/contest/1111/problem/D
题意有点复杂,这里不说了
主要是这里学习到了一个思想,这个思想和背包的过程是互通的:
使用前i+1个物品达成j点消费的方法数=
只使用前i个物品的方法数+使用了第(i+1)个物品的方法数=
只是用前i个物品的方法数+使用前i个物品达成(j-Cost[i+1])的方法数
代码:
//Problem:
//Date:
//Skill:
//Bug:
/Definations/
//循环控制
#define CLR(a) memset((a),0,sizeof(a))
#define RE(i,n) for(int i=0;i<int(n);i++)
#define RE2(i,n) for(int i=1;i<=int(n);i++)
#define FOR(x,vec) for(vector<int>::iterator it=vec.begin();it!=vec.end();++it) { int &x(*it);
//输入输出
#define INC(c) do{scanf("%c",&c);}while(isspace(c))
#define ON cout<<endl
#define PII pair<int,int>
using namespace std;
const int inf = 0x3f3f3f3f;
const long long llinf = 0x3f3f3f3f3f3f3f3f;
Options//
typedef long long ll;
#define stdcpph
#define CPP_IO
#ifdef stdcpph
#include<bits/stdc++.h>
#else
#include<ctype.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<algorithm>
#include<functional>
#ifdef CPP_IO
#include<iostream>
#include<iomanip>
#include<string>
#else
#include<stdio.h>
#endif
#endif
Basic Functions//
template<typename INint>
inline void IN(INint &x)
{
x = 0; int f = 1; char c; cin.get(c);
while (c<'0' || c>'9') { if (c == '-')f = -1; cin.get(c); }
while (c >= '0'&&c <= '9') { x = x * 10 + c - '0'; cin.get(c); }
x *= f;
}
template<typename INint>
inline void OUT(INint x)
{
if (x > 9)OUT(x / 10);
cout.put(x % 10 + '0');
}
Added Functions//
//How to think:
//先认真读题,把题目逻辑化,读清全部条件,再做,不然,哼哼
//写题的时候遇到的一些”莫名“的错误大部分是自己的代码写错了一个变量
//1.分治 2.容斥 3.化多元为单元
//4.dp 分阶段,后阶段受前阶段的影响
//5.凡是有很大的指数的,都可以先用log算一下
//6.预处理,作用非常大,很快
//
//1.Do you use cout/cin? Do not use!
//2.what's the maximum Int data? Is it beyond I32d?
//3.Ever Mod after neccesary caEdlculation?
//4.Ever Cleaned the array before using?
const int maxn = int(100);
const int maxm = 1e5 + 8;
const int mod = 1e9 + 7;
ll Add(ll a, ll b){
ll c(a + b);
return c >= mod ? c - mod : c;
}
ll Plus(ll a, ll b){
ll c(a - b);
return c < 0 ? c + mod : c;
}
ll Mul(ll a, ll b){
ll c(a*b);
return c % mod;
}
ll ans[maxn][maxn] = { 1 };//使用
ll cnt[maxn] = { 0 };
ll invcnt[maxn];
ll fac[maxm] = { 1 };
ll ans0;
ll dp[maxm] = { 1 };//使用全部物品,达到i
ll temp[maxm];
ll temp2[maxm];
string s;
ll len;
ll tonum(char c)
{
if (c <= 'Z'&&c >= 'A')return c - 'A' + 1;
else return c - 'a' + 1 + 26;
}
ll qpow(ll a, ll b, ll p) //求a^bMODp
{
ll ret = 1;
while (b)
{
if (b & 1)
ret = (ret * a) % p;
a = (a * a) % p;
b >>= 1;
}
return ret;
}
求逆元//
费马小定理
ll inv(ll a, ll p) //返回a对p的逆元
{
return qpow(a, p - 2, p);
}
Code/
int main()
{
//freopen("C:\\Users\\VULCAN\\Desktop\\data.in", "r", stdin);
ll T(1), times(0);
#ifdef CPP_IO// CPP_IO
std::ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
//cin >> T;
#else
//IN(T);
#endif
/
while (++times, T--)
{
cin >> s; s = ' ' + s;
len = s.length() - 1;
RE2(i, s.length() - 1)
++cnt[tonum(s[i])];
RE2(i, 52)
{
if (!cnt[i])continue;
for (ll j = len / 2; j >= cnt[i]; --j)
dp[j] = Add(dp[j], dp[j - cnt[i]]);
}
RE2(i, 52)
if (cnt[i])
{
ans[i][i] = dp[len / 2];
}
RE2(i, 52)
{
memcpy(temp, dp, sizeof(dp));
//for (ll j = len / 2; j >= cnt[i]; --j)
for (ll j = cnt[i]; j <= len / 2; ++j)
temp[j] = Plus(temp[j], temp[j - cnt[i]]);
for (ll j = i + 1; j <= 52; ++j)
{
memcpy(temp2, temp, sizeof(temp));
//for (ll k = len / 2; k >= cnt[j]; --k)
for (ll k = cnt[j]; k <= len / 2; ++k)
{
//temp2[k] -= temp2[k - cnt[j]];
temp2[k] = Plus(temp2[k], temp2[k - cnt[j]]);
}
//ans[i][j] = ans[j][i] = temp2[len / 2 - cnt[i] - cnt[j]];
ans[i][j] = ans[j][i] = Add(temp2[len / 2],temp2[len/2]);
}
}
RE2(i, len)fac[i] = Mul(fac[i - 1], i);
ans0 = Mul(fac[len / 2], fac[len / 2]);
RE2(i, 52)
{
//if (!cnt[i])continue;
ans0 = Mul(ans0, inv(fac[cnt[i]], mod));
}
int q; cin >> q;
RE2(i, q)
{
int l, r; cin >> l >> r;
l = tonum(s[l]); r = tonum(s[r]);
cout << ans[l][r]*ans0%mod << endl;
}
}
/
return 0;
}