题目链接
题意:
有 n 个 1 , m 个 4 , k 个 2 有n个1,m个4,k个2 有n个1,m个4,k个2
组 成 一 个 序 列 问 最 多 能 有 多 少 子 序 列 是 1412 组成一个序列问最多能有多少子序列是1412 组成一个序列问最多能有多少子序列是1412
题解:
摆 成 11 … 1122 … 2211 … 1144 … … 的 样 子 摆成11…1122…2211…1144……的样子 摆成11…1122…2211…1144……的样子
这 样 能 使 得 每 个 数 都 有 贡 献 这样能使得每个数都有贡献 这样能使得每个数都有贡献
根 据 和 一 样 , 两 数 差 最 小 乘 积 最 大 可 以 知 道 平 分 1 即 可 根据和一样,两数差最小乘积最大可以知道平分1即可 根据和一样,两数差最小乘积最大可以知道平分1即可
四 个 位 置 个 数 相 乘 四个位置个数相乘 四个位置个数相乘
#include
using namespace std;
int main(){
int _;
scanf("%d",&_);
while(_--){
long long n,m,k;
scanf("%lld%lld%lld",&n,&m,&k);
printf("%lld\n",(n/2)*m*k*(n-n/2));
}
}
题意:
给 一 棵 树 , 问 每 个 点 有 多 少 和 他 距 离 为 2 的 点 给一棵树,问每个点有多少和他距离为2的点 给一棵树,问每个点有多少和他距离为2的点
题解:
对 于 每 个 点 来 说 , 距 离 为 2 的 点 , 就 是 这 个 点 的 子 节 点 的 子 节 点 对于每个点来说,距离为2的点,就是这个点的子节点的子节点 对于每个点来说,距离为2的点,就是这个点的子节点的子节点
统 计 一 下 这 个 点 相 连 的 点 , 每 个 点 的 度 数 统计一下这个点相连的点,每个点的度数 统计一下这个点相连的点,每个点的度数
但 由 于 是 双 向 边 , 需 要 去 除 自 己 的 贡 献 但由于是双向边,需要去除自己的贡献 但由于是双向边,需要去除自己的贡献
AC代码
/*
Author:zzugzx
Lang:C++
Blog:blog.csdn.net/qq_43756519
*/
#include
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
ll ans[maxn];
vector<int> g[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n;cin>>n;
for(int i=1,u,v;i<n;i++){
cin>>u>>v;
g[u].pb(v);
g[v].pb(u);
}
for(int u=1;u<=n;u++){
ll ans=0;
for(auto v:g[u]){
if(v==u)continue;
ans+=g[v].size()-1;
}
cout<<ans<<endl;
}
return 0;
}
题意:
给 一 个 长 度 为 n 的 数 组 给一个长度为n的数组 给一个长度为n的数组
求 ∑ l = 1 n ∑ r = l n ∑ i = l r ∑ j = i r a i ∗ a j m o d 1 e 9 + 7 求\sum_{l=1}^n\sum_{r=l}^n\sum_{i=l}^r\sum_{j=i}^ra_i*a_j~mod~1e9+7 求∑l=1n∑r=ln∑i=lr∑j=irai∗aj mod 1e9+7
题解:
n < = 2 e 5 , 很 大 n<=2e5,很大 n<=2e5,很大
暴 力 求 解 就 不 用 想 了 , 考 虑 一 下 怎 么 样 化 简 暴力求解就不用想了,考虑一下怎么样化简 暴力求解就不用想了,考虑一下怎么样化简
自 己 举 个 例 子 感 受 一 下 , 不 要 太 多 数 自己举个例子感受一下,不要太多数 自己举个例子感受一下,不要太多数
我 这 里 举 4 个 数 , 1 , 2 , 3 , 4 我这里举4个数,1,2,3,4 我这里举4个数,1,2,3,4
然 后 先 走 前 两 个 确 定 , 结 果 是 1 然后先走前两个确定,结果是1 然后先走前两个确定,结果是1
然 后 第 一 个 不 变 , 第 二 个 累 加 区 间 加 然后第一个不变,第二个累加区间加 然后第一个不变,第二个累加区间加
得 到 1 ∗ 1 + 1 ∗ 2 + 2 ∗ 2 得到1*1+1*2+2*2 得到1∗1+1∗2+2∗2
再 变 一 次 1 ∗ 1 + 1 ∗ 2 + 1 ∗ 3 + 2 ∗ 2 + 2 ∗ 3 + 3 ∗ 3 再变一次1*1+1*2+1*3+2*2+2*3+3*3 再变一次1∗1+1∗2+1∗3+2∗2+2∗3+3∗3
1 ∗ 1 + 1 ∗ 2 + 1 ∗ 3 + 1 ∗ 4 + 2 ∗ 2 + 2 ∗ 3 + 2 ∗ 4 + 3 ∗ 3 + 3 ∗ 4 + 4 ∗ 4 1*1+1*2+1*3+1*4+2*2+2*3+2*4+3*3+3*4+4*4 1∗1+1∗2+1∗3+1∗4+2∗2+2∗3+2∗4+3∗3+3∗4+4∗4
这 样 第 一 个 累 加 为 1 的 时 候 跑 完 了 这样第一个累加为1的时候跑完了 这样第一个累加为1的时候跑完了
我 们 可 以 化 简 一 下 我们可以化简一下 我们可以化简一下
1 ∗ ( 1 + 1 + 2 + 1 + 2 + 3 + 1 + 2 + 3 + 4 ) 1*(1+1+2+1+2+3+1+2+3+4) 1∗(1+1+2+1+2+3+1+2+3+4)
2 ∗ ( 2 + 2 + 3 + 2 + 3 + 4 ) 2*(2+2+3+2+3+4) 2∗(2+2+3+2+3+4)
3 ∗ ( 3 + 3 + 4 ) 3*(3+3+4) 3∗(3+3+4)
4 ∗ 4 4*4 4∗4
然 后 可 以 想 象 一 下 , 或 者 大 概 再 往 后 下 一 点 就 能 发 现 然后可以想象一下,或者大概再往后下一点就能发现 然后可以想象一下,或者大概再往后下一点就能发现
第 一 个 累 加 为 2 的 时 候 , 其 实 就 是 这 式 子 里 的 后 三 个 第一个累加为2的时候,其实就是这式子里的后三个 第一个累加为2的时候,其实就是这式子里的后三个
为 3 的 时 候 是 后 两 个 为3的时候是后两个 为3的时候是后两个
这 规 律 就 找 到 了 这规律就找到了 这规律就找到了
我 们 只 要 把 这 些 括 号 里 的 东 西 算 出 来 和 数 相 乘 , 最 后 求 一 下 后 缀 的 后 缀 就 是 答 案 了 我们只要把这些括号里的东西算出来和数相乘,最后求一下后缀的后缀就是答案了 我们只要把这些括号里的东西算出来和数相乘,最后求一下后缀的后缀就是答案了
括 号 里 的 可 以 用 个 数 算 , 我 们 可 以 发 现 第 i 个 数 一 共 有 n − i + 1 个 括号里的可以用个数算,我们可以发现第i个数一共有n-i+1个 括号里的可以用个数算,我们可以发现第i个数一共有n−i+1个
然 后 我 们 用 后 缀 跑 一 下 每 个 括 号 里 每 个 数 的 个 数 乘 对 应 的 值 然后我们用后缀跑一下每个括号里每个数的个数乘对应的值 然后我们用后缀跑一下每个括号里每个数的个数乘对应的值
这 样 括 号 里 的 东 西 算 出 来 了 , 假 设 是 s u m i 这样括号里的东西算出来了,假设是sum_i 这样括号里的东西算出来了,假设是sumi
∑ i = 1 n a i ∗ s u m i 就 是 第 一 个 累 加 为 1 时 候 的 结 果 \sum_{i=1}^na_i*sum_i就是第一个累加为1时候的结果 ∑i=1nai∗sumi就是第一个累加为1时候的结果
∑ i = 2 n a i ∗ s u m i 就 是 第 一 个 累 加 为 2 时 候 的 结 果 \sum_{i=2}^na_i*sum_i就是第一个累加为2时候的结果 ∑i=2nai∗sumi就是第一个累加为2时候的结果
所 以 这 个 时 候 我 们 就 需 要 求 一 下 后 缀 的 后 缀 算 出 来 第 一 个 累 加 为 1 到 n 全 部 的 和 所以这个时候我们就需要求一下后缀的后缀算出来第一个累加为1到n全部的和 所以这个时候我们就需要求一下后缀的后缀算出来第一个累加为1到n全部的和
但 其 实 有 更 简 便 的 方 法 , 我 们 直 接 记 个 数 但其实有更简便的方法,我们直接记个数 但其实有更简便的方法,我们直接记个数
假 设 下 标 为 i 的 a i ∗ s u m i 我 们 用 的 次 数 应 该 是 i 次 假设下标为i的a_i*sum_i我们用的次数应该是i次 假设下标为i的ai∗sumi我们用的次数应该是i次
所 以 i 从 1 到 n 直 接 将 每 个 值 乘 他 的 贡 献 次 数 就 是 最 终 答 案 所以i从1到n直接将每个值乘他的贡献次数就是最终答案 所以i从1到n直接将每个值乘他的贡献次数就是最终答案
如 果 你 感 觉 这 样 的 规 律 不 好 看 出 来 如果你感觉这样的规律不好看出来 如果你感觉这样的规律不好看出来
那 你 可 以 考 虑 , 去 掉 两 层 内 部 的 累 加 , 用 代 码 输 出 一 下 找 一 下 规 律 那你可以考虑,去掉两层内部的累加,用代码输出一下找一下规律 那你可以考虑,去掉两层内部的累加,用代码输出一下找一下规律
这 个 规 律 应 该 也 很 好 看 出 , 其 实 就 是 我 在 上 面 说 的 规 律 这个规律应该也很好看出,其实就是我在上面说的规律 这个规律应该也很好看出,其实就是我在上面说的规律
但 是 会 更 加 直 观 但是会更加直观 但是会更加直观
AC代码
/*
Author:zzugzx
Lang:C++
Blog:blog.csdn.net/qq_43756519
*/
#include
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
ll Pow(ll a, ll b){
ll ans = 1;
while(b > 0){
if(b & 1){
ans = ans * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return ans;
}
ll a[maxn],s1[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=n;i;i--)
s1[i]=(s1[i+1]+a[i]*(n-i+1)%mod)%mod;
ll ans=0;
for(int i=1;i<=n;i++)
ans=(ans+i*a[i]%mod*s1[i]%mod)%mod;;
cout<<ans;
return 0;
}
题意:
n 个 宝 石 放 进 n 个 盒 子 n个宝石放进n个盒子 n个宝石放进n个盒子
如 果 第 i 种 宝 石 不 能 放 到 a i 盒 子 有 多 少 种 方 案 如果第i种宝石不能放到a_i盒子有多少种方案 如果第i种宝石不能放到ai盒子有多少种方案
m o d 998244353 mod~998244353 mod 998244353
题解:
如 果 是 直 接 写 , 我 们 需 要 考 虑 对 于 第 i 种 宝 石 如果是直接写,我们需要考虑对于第i种宝石 如果是直接写,我们需要考虑对于第i种宝石
a i 盒 子 是 否 已 经 被 放 了 宝 石 , 最 后 得 出 的 会 是 两 种 情 况 a_i盒子是否已经被放了宝石,最后得出的会是两种情况 ai盒子是否已经被放了宝石,最后得出的会是两种情况
我 们 很 难 统 计 这 两 种 情 况 我们很难统计这两种情况 我们很难统计这两种情况
那 就 倒 着 写 , 先 随 意 放 , 看 看 其 中 有 多 少 不 合 法 的 方 案 那就倒着写,先随意放,看看其中有多少不合法的方案 那就倒着写,先随意放,看看其中有多少不合法的方案
总 方 案 很 好 求 , 就 是 n ! 总方案很好求,就是n! 总方案很好求,就是n!
现 在 需 要 求 的 是 不 合 法 的 方 案 现在需要求的是不合法的方案 现在需要求的是不合法的方案
不 合 法 的 方 案 就 是 某 个 盒 子 放 了 不 该 放 的 宝 石 不合法的方案就是某个盒子放了不该放的宝石 不合法的方案就是某个盒子放了不该放的宝石
我 们 需 要 统 计 最 后 有 用 的 就 是 i 个 盒 子 放 了 不 该 放 的 宝 石 的 方 案 我们需要统计最后有用的就是i个盒子放了不该放的宝石的方案 我们需要统计最后有用的就是i个盒子放了不该放的宝石的方案
但 是 恰 好 i 个 我 们 很 难 求 出 , 我 们 可 以 用 至 少 有 i 个 盒 子 放 了 不 该 放 的 宝 石 但是恰好i个我们很难求出,我们可以用至少有i个盒子放了不该放的宝石 但是恰好i个我们很难求出,我们可以用至少有i个盒子放了不该放的宝石
如 果 是 至 少 i 个 盒 子 , 那 么 肯 定 有 重 复 的 方 案 如果是至少i个盒子,那么肯定有重复的方案 如果是至少i个盒子,那么肯定有重复的方案
这 时 候 就 可 以 用 的 容 斥 原 理 了 , 奇 数 加 偶 数 减 , 容 斥 原 理 就 不 多 说 这时候就可以用的容斥原理了,奇数加偶数减,容斥原理就不多说 这时候就可以用的容斥原理了,奇数加偶数减,容斥原理就不多说
现 在 开 始 开 始 说 怎 么 求 至 少 i 个 盒 子 放 了 不 该 放 的 现在开始开始说怎么求至少i个盒子放了不该放的 现在开始开始说怎么求至少i个盒子放了不该放的
其 实 就 是 统 计 出 哪 几 个 位 置 , 有 几 个 不 该 放 的 宝 石 其实就是统计出哪几个位置,有几个不该放的宝石 其实就是统计出哪几个位置,有几个不该放的宝石
不 该 放 的 宝 石 个 数 , 就 是 这 一 个 点 的 方 案 数 不该放的宝石个数,就是这一个点的方案数 不该放的宝石个数,就是这一个点的方案数
对 于 多 个 位 置 就 是 相 乘 起 来 对于多个位置就是相乘起来 对于多个位置就是相乘起来
由 于 统 计 的 是 需 要 将 所 有 宝 石 放 入 , 对 于 其 他 宝 石 也 需 要 进 行 放 入 由于统计的是需要将所有宝石放入,对于其他宝石也需要进行放入 由于统计的是需要将所有宝石放入,对于其他宝石也需要进行放入
那 么 就 是 乘 剩 余 没 有 选 择 的 个 数 的 阶 乘 , 我 们 已 经 选 择 的 是 确 定 不 合 法 的 那么就是乘剩余没有选择的个数的阶乘,我们已经选择的是确定不合法的 那么就是乘剩余没有选择的个数的阶乘,我们已经选择的是确定不合法的
这 一 过 程 我 们 可 以 使 用 01 背 包 + 滚 动 数 组 实 现 这一过程我们可以使用01背包+滚动数组实现 这一过程我们可以使用01背包+滚动数组实现
状 态 转 移 很 简 单 , 就 是 d p [ j ] = d p [ j − 1 ] ∗ a [ i ] 状态转移很简单,就是dp[j]=dp[j-1]*a[i] 状态转移很简单,就是dp[j]=dp[j−1]∗a[i]
求 出 来 的 是 我 们 确 定 不 合 法 的 盒 子 数 求出来的是我们确定不合法的盒子数 求出来的是我们确定不合法的盒子数
然 后 剩 下 的 就 是 把 他 乘 上 对 应 的 阶 乘 形 成 完 整 方 案 , 然 后 进 行 容 斥 去 重 即 可 然后剩下的就是把他乘上对应的阶乘形成完整方案,然后进行容斥去重即可 然后剩下的就是把他乘上对应的阶乘形成完整方案,然后进行容斥去重即可
最 后 用 总 数 减 去 这 个 算 出 来 的 数 最后用总数减去这个算出来的数 最后用总数减去这个算出来的数
AC代码
/*
Author:zzugzx
Lang:C++
Blog:blog.csdn.net/qq_43756519
*/
#include
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
ll fac[maxn],dp[maxn],a[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n;cin>>n;fac[0]=1;
for(int i=1,x;i<=n;i++){
cin>>x;
a[x]++;
fac[i]=fac[i-1]*i%mod;
}
dp[0]=1;
for(int i=1;i<=n;i++)
for(int j=i;j>=0;j--)
dp[j+1]=(dp[j+1]+dp[j]*a[i]%mod)%mod;
ll ans=fac[n],res=0;
for(int i=1,p=1;i<=n;i++,p=-p)
res=(res+fac[n-i]*dp[i]*p%mod+mod)%mod;
cout<<(ans-res+mod)%mod;
return 0;
}