一共存在有 m 个事件,且事件分为以下的 3 种类型。
1.小 Z 得到了 a 元压岁钱。
2.小 Z 花掉了 a 元压岁钱用于买皮肤。
3.小 Z 把自己的 a 元钱封印了起来,只有当第 b 个事件发生前 1 秒才会解除封印,并保证每次小 Z 现有的钱大于等于封印的钱。
当小 Z 的钱在某个事件不够花时,小 Z 会感到不开心,同时钱不够花时小 Z 便不会花钱。
请告诉小 Z ,他的钱在几个事件中会不够花。
签到题, 此题%70的数据其实根本就没有第三种类型, 所以:直接按题意模拟即可。对于封印, 可以开一个map。 下表指的是解印的那天, 对应的数值是解印的钱数;对天数依次遍历, 每次先把当前解开封印的钱数加到持有钱里即可, 记住随时判钱是否够, 及时统计;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
ll m;
ll money;
ll ans;
map<ll, ll> mp;
int main()
{
cin >> m;
for(ll i = 1; i <= m; i++)
{
int t;
cin >> t;
money += mp[i];
if(t == 1)
{
int a;
cin >> a;
money += a;
}
else if(t == 2)
{
int a;
cin >> a;
if(money < a)
{
ans++;
}
else
{
money -= a;
}
}
else
{
int a, b;
cin >> a >> b;
money -= a;
mp[b] += a;
}
}
cout << ans << endl;
return 0;
}
哦, 对了!!!!
别忘了开long long!!!
给定 n 张牌,牌的大小为 1∼10。你需要挑选其中的 n−2 张牌加起来是 10 的倍数,另外两张牌和的个位数即为你所获得的点数。特别地,如果这两张牌的和是 10 的倍数,则点数为 10,也叫做牛哄哄。如果任意 n−2 张牌不能构成 10 的倍数,则点数为 0,也叫做牛不拢。
由于小 Z 想要更开心的玩耍,所以需要你来完成这个程序来帮助小 Z 在 1 秒内知道点数。
这道题当时在考场上一想就出来了
这道题打算用分层的思路来讲:
因为这道题子任务很重;ok, 让我们来看一下
当时想的是枚举所有三张牌的组合。。。。25复杂度;
进行判断即可;
for(int i = 1; i <= 5; i++)
{
for(int j = i+1; j <= 5; j++)
{
for(int k = j+1; k <= 5; k++)
{
....
}
}
}
显然, 选n-2个数肯定超时, 因为你不可能进行n-2次循环吧。。。。
但我们可以反向思维 逃)如果我们选出两个数来了, 那么。。。剩下的n-2个数不也都确定了吗!!!
那么怎么判断呢: 简单, 记录所有数的和, 为sum;
用sum 减去那两个数就是n-2个数的和了呗, 再进行判断
for(int i = 1; i <= n; i++)
{
for(int j = i+1; j <= n; j++)
{
int total = a[i] + a[j];
if((sum - total) % 10 == 0)
{
if(total % 10 == 0)
{
cout << 10 << endl;
}
else
{
cout << total % 10 << endl;
}
return 0;
}
}
}
时间复杂度O(n*n)
由此可见,O(n2)的时间复杂度已经过不了了;
这次, 我们抓住特点:卡牌上的数字只有1~10!!!
所以所有的两张不同类型搭配,也就是只有那么几种呗;
考虑枚举卡牌上的内容而不是卡牌了:考虑有重复的情况;开一个数组s记录每张牌出现的次数, 对于重复先判断:当且仅当s[i] >= 2时才有重复可能;
时间复杂度O(n);
for(int i = 1; i <= n; i++)
{
cin >> a[i];
s[a[i]]++;
sum += a[i];
}
if(sum % 10 == 0)
{
cout << 10 << endl;
return 0;
}
for(int i = 1; i <= 10; i++)
{
if(s[i] >= 2 && (sum - i * 2) % 10 == 0)
{
cout << i*2 % 10 << endl;
return 0;
}
}
for(int i = 1; i < 10; i++)
{
for(int j = i+1; j <= 10; j++)
{
if(s[i] > 0 && s[j] > 0 && (sum - i - j) % 10 == 0)
{
cout << (i+j) % 10 << endl;
return 0;
}
}
}
cout << 0 << endl;
有一个牌堆,一共有 n 张牌,第 i 张牌上有一个数 ai,其中第一张牌是堆顶。
小 Z 先取牌,他可以从堆顶开始取连续若干张牌(可以取 000 张),取完的牌拿在手上,也就是不在牌堆里了。
然后小 Y 取牌,同样,她也可以从堆顶开始取连续若干张牌(可以取 若干 张)。
如果一个人手上的牌的数字和大于 X,那么他的分数就是 0,否则分数就是取得牌上的数字和。
分数高的人获胜,如果一样高,则无人获胜。
小 Z 为了获胜,使用了透视挂,即他知道牌堆里每张牌上写的数。
现在问你对于满足 1 ≤ X ≤ K 1 \leq X \leq K 1≤X≤K的所有整数 X,哪些可以使得小 Z 有必胜策略,即小 Z 取完后,不管小 Y 怎么取都一定会输。
第一: 游戏只有一个回合;第二:上面加粗字体
直接排除不取的情况, 因为不取的话分数为0, 就一定赢不了小Y;其实我们要找的X都是一个临界点, 小Y多拿一张就爆了, 少拿一张就和法那样的临界点;所以根据这两种状况进行判断即可;
那是如何转移, 现在想怎么表示状态;看到连续取牌, 想到区间求和:设 S i , j S_{i, j} Si,j表示从i到j的区间和;则由于小z是从堆顶开始取得,设小Z取了x张牌, 所以小Z的分数为 S 1 , x S_{1, x} S1,x;小Y接着去取, 设小Y取到y, 则小Y的分数为 S x + 1 , y S_{x+1, y} Sx+1,y
那么要求就是
1 ≤ S x + 1 , y < S 1 , x ≤ X ≤ K 1 \leq S_{x+1, y} \lt S_{1, x} \leq X \leq K 1≤Sx+1,y<S1,x≤X≤K
又因为 S x + 1 , y = S 1 , y − S 1 , x S_{x+1, y} = S_{1, y} - S_{1, x} Sx+1,y=S1,y−S1,x
所以
1 ≤ S 1 , y − S 1 , x < S 1 , x ≤ X ≤ K 1 \leq S_{1, y} - S_{1, x} \lt S_{1, x} \leq X \leq K 1≤S1,y−S1,x<S1,x≤X≤K
后面再推就是用二分了, 但我可以用枚举:核心思想:
每一次枚举的状态从上一次的状态开始就可以了
我也不知道为啥,蒟蒻求助~~~
long long a[N],now1,now2;
int now,ans[N],n,k,j=1,z=2;
bool flag;
读入略。。。
if(k==1){printf("0");return 0;}
for(int i=1;i<=k;++i){
for(;j<=n;++j){
now1=now2=flag=0;
if(a[j]>i)break;
else now1=a[j];
for(;z<=n;++z){
now2=a[z]-a[j];
if(now2>i&&now1>0)break;
if(now2>=now1){flag=1;break;}
}
if(!flag){ans[++now]=i;break;}
}
}
printf("%d\n",now);
for(int i=1;i<=now;++i)printf("%d ",ans[i]);
学校组织了一次暑期出游活动,报名将在第 T 天截止。
一共有 n 位同学,第 iii 位同学有 a i a_i ai 位朋友。朋友关系是单向的,换句话说,小 Z 有一个朋友是小 Y,并不意味着小 Y 一定也有一个朋友是小 Z。另外,自己也可能是自己的朋友。
第 0 天时,每位同学会决定自己是否参加活动。第 i 位同学有 pi 的概率决定参加,1-pi 的概率决定不参加。
接下来的 T 天里,每位同学会重新决定自己是否参加活动。第 i 位同学这一天决定参加活动,当且仅当至少有一个他的朋友在前一天决定参加,否则便不参加。你需要求出参加活动的同学人数期望,答案对 998244353取模。
先抛掉概率不看(因为我不会)就是问有一些朋友然后加上上面加粗字体的条件, 我们就可以转化成::给定n个点的有向图, 一开始选择一些点, 每次走一步, 问T步后可能在哪;
显然,可以用bitset加矩阵乘法优化
bitset 是啥? 看这儿!!!bitset简介
矩阵不用我说了吧。。。。
下面来构造一个矩阵;
矩阵 j a i 1 0 b 0 1 \begin{array}{c|l} \text{矩阵} & j & a\\ \hline i & 1 & 0\\ b & 0 & 1 \end{array} 矩阵ibj10a01
说实话, 过于简单了。。
这个矩阵就是一个01矩阵, 下面讲解意义;
1.横纵坐标都是人, 共2 * n 个;
2.中间的数设为 a i j a_{ij} aij表示如果选i, 那么j最终就会被走到;
一次转移就是
if (a.a[i][j]) c.a[i]|=b.a[j];
这就是矩阵乘法的设立:
用语言翻译就是:如果选 i 能走到 j, 那么选 j 能走到的点选 i 也能走到;
是不是清楚了很多呢;
用图来表示::
所以转移就是建边啦。。。
矩阵乘上自己一次相当于过了一天, 那么T天后就是乘了T次自己呗;
用矩阵快速幂就能解决, 得到最终矩阵final;
下面来想如何算答案:
首先知道一件事, 答案 就是每个人去的概率之和
然后, 在模意义下计算;;
遍历每一个人, 算出他去的概率, 设为qi,那么可以算她不去的概率再用1减去;
对于他自己, 遍历矩阵中和他为朋友的人(以他为纵坐标为一的人), 算出他们不去的概率乘起来就是他不去的概率啦;
1 − q i = ∏ f i n a l . a [ j ] [ i ] = 1 ( 1 − p j ) 1 - q_i = \prod_{final.a[j][i] = 1} (1 - p_j) 1−qi=final.a[j][i]=1∏(1−pj)
pj是他朋友的概率, 最后答案等于
a n s = ∑ i = 1 n q [ i ] ans = \sum_{i=1} ^ n q[i] ans=i=1∑nq[i]
然后别忘了取模
a n s = ( a n s 取 模 m o d + m o d ) 取 模 m o d ans = (ans取模mod + mod) 取模mod ans=(ans取模mod+mod)取模mod
不要问我为什么因为我也不知道, 大佬求助~~;
#include
#include
#include
#include
using namespace std;
const int N=510,MOD=998244353;
int n,m,ans,p[N];
struct matrix
{
bitset<N> a[N];
friend matrix operator *(matrix &a,matrix &b)
{
matrix c;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (a.a[i][j]) c.a[i]|=b.a[j];
return c;
}
}a,f;
int main()
{
scanf("%d%d",&n,&m);
for (int i=1,x,y;i<=n;i++)
{
f.a[i][i]=1;
scanf("%d%d",&p[i],&x);
while (x--)
{
scanf("%d",&y);
a.a[y][i]=1;
}
}
for (;m;m>>=1,a=a*a)
if (m&1) f=f*a;
for (int i=1;i<=n;i++)
{
int x=1;
for (int j=1;j<=n;j++)
if (f.a[j][i])
x=1LL*x*(1-p[j])%MOD;
ans=(ans+1-x)%MOD;
}
printf("%d",(ans%MOD+MOD)%MOD);
return 0;
}
不知道写啥, 主要是记录一下思路吧, 写的不好谅解一下,对了,里面的问题请大佬一看;
1.最后为何要(ans % mod + mod)%mod
2. 状态为何不用重新枚举(C题)
谢谢!