7/12
好多典,不会,坏。
已过非太水的题们
//C
//https://ac.nowcoder.com/acm/contest/46814/C
//贪心小典
#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
#define int ll
#define pb push_back
#define eb emplace_back
#define m_p make_pair
#define mod 1000000007
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define inf 0x3f3f3f3f3f3f3f3f
const int N = 3e5 + 50;
int arr[N];
int b[N];
void work() {
int n;cin>>n;
for(int i=1;i<=n/2;i++){
if(i&1){
arr[i]=i*2-1;
arr[n-i+1]=i*2;
}else{
arr[n-i+1]=i*2-1;
arr[i]=i*2;
}
}
if(n&1){
arr[n/2+1]=n;
}
for(int i=1;i<=n;++i){
b[i]=arr[i];
}
int ans=0;
for(int i=n;i>=1;--i){
for(int j=1;j<i;++j){
arr[j]+=arr[j+1];
arr[j]%=mod;
}
}
arr[1]%=mod;
cout<<arr[1]<<'\n';
for(int i=1;i<=n;++i){
cout<<b[i]<<" \n"[i==n];
}
}
signed main() {
io;
work();
return 0;
}
//F
//https://ac.nowcoder.com/acm/contest/46814/F
//优先队列预处理
#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
#define int ll
#define pb push_back
#define eb emplace_back
#define m_p make_pair
#define mod 998244353
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define inf 0x3f3f3f3f3f3f3f3f
const int N = 1e9 + 10;
int arr[200005];
//int ans[N];
void work() {
int n,q;cin>>n>>q;
priority_queue<int>pq;
for(int i=1;i<=n;++i){
cin>>arr[i];
pq.push(arr[i]);
}
int l=1;
map<int,int>ans;
while(pq.top()!=1ll&&(!pq.empty())){
int t=pq.top();pq.pop();
int a=__builtin_popcount(t);
pq.push(a);
ans[l]=pq.top();
l++;
if(l>1e9){
break;
}
}
while(q--){
int k;cin>>k;
if(!ans[k]){
cout<<"1\n";continue;
}else cout<<ans[k]<<'\n';
}
}
signed main() {
io;
work();
return 0;
}
//I
//https://ac.nowcoder.com/acm/contest/46814/I
//诈骗bfs,感觉这次写的小而美
#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
#define int ll
#define pb push_back
#define eb emplace_back
#define m_p make_pair
#define mod 998244353
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define inf 0x3f3f3f3f3f3f3f3f
const int N = 3e5 + 50;
vector<int>a[N];
bool vis[N];
map<pii,int>mp;
int n,m;
int minn;
void bfs(int num){
queue<pii>q;
vis[num]=1;
q.push(m_p(num,0));
while(!q.empty()){
pii t=q.front();q.pop();
int x=t.first,y=t.second;
if(x==n){
minn=y;
}
for(auto to:a[x]){
if(!vis[to]){
q.push(m_p(to,y+1));
vis[to]=1;
}
}
}
}
void work() {
cin>>n>>m;
for(int i=1;i<=m;++i){
int u,v,w;
cin>>u>>v>>w;
mp[m_p(u,v)]=w;
mp[m_p(v,u)]=w;
a[u].pb(v);
a[v].pb(u);
}
if(a[1].size()>1){
bfs(1);
cout<<minn<<'\n';
}else{
int to=a[1][0];
bfs(to);
if(m>minn+1){
cout<<minn+1<<'\n';
}
else{
int ans=mp[m_p(1,to)];
ans+=minn;
cout<<ans<<'\n';
}
}
}
signed main() {
io;
work();
return 0;
}
//D
//https://ac.nowcoder.com/acm/contest/46814/D
//字符串小典
#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
#define int ll
#define pb push_back
#define eb emplace_back
#define m_p make_pair
#define mod 998244353
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define inf 0x3f3f3f3f3f3f3f3f
const int N = 3e5 + 50;
int pre[N],suf[N];
int sum[N],c[N],f[N];
void work() {
string s;cin>>s;
int n=s.length();
//法1
s=' '+s;
for(int i=1;i<=n;++i){
pre[i]=pre[i-1]+(s[i]=='u'?1:0);
}
for(int i=n;i>0;--i){
suf[i]=suf[i+1]+(s[i]=='u'?1:0);
}
int ee=0,idx=-1;
for(int i=1;i<=n;++i){
if(s[i]=='d'){
c[1]+=suf[i];
c[i]-=suf[i];
c[i+1]+=pre[i];
f[i]=pre[i]*suf[i];
}
}
for(int i=1;i<=n;++i){
sum[i]=sum[i-1]+c[i];
if(s[i]=='u') f[i]=sum[i];
}
for(int i=1;i<=n;++i){
if(f[i]>ee){
ee=f[i];
idx=i;
}
}
if(idx!=-1){
s[idx]='a';
}
s.erase(s.begin(),s.begin()+1);
cout<<s<<'\n';
//法2
//只需要比较最左最右的u和所有d即可。贪心地,最左or最右的u一定是贡献最大的。
/*
vector<int>d;
int l=0,r=n-1;
bool f1=0,f2=0;
for(int i=0;i<n;++i){
if(s[i]=='u'){
pre[i]++;
if(f1==0){
l=i;f1=1;
}
}
if(s[i]=='d'){
d.pb(i);
}
}
for(int i=n-1;i>=0;--i){
if(s[i]=='u'){
suf[i]++;
if(f2==0){
f2=1;r=i;
}
}
}
for(int i=1;i<n;++i){
pre[i]+=pre[i-1];
}
for(int i=n-2;i>=0;--i){
suf[i]+=suf[i+1];
}
if(d.size()==0){
cout<<s<<'\n';
return;
}
int ddd=0;
int pru=0,suu=0;
int mid=0;
for(int i=0;i<d.size();++i){
int to=d[i];
int res=pre[to]*suf[to];
if(res>ddd){
mid=to;
ddd=max(ddd,res);
}
if(to>l){
pru+=suf[to];
}
if(to<r){
suu+=pre[to];
}
}
if(ddd>pru){
if(ddd>suu){
s[mid]+=1;
}else{
s[r]+=1;
}
}else{
if(pru>suu){
s[l]+=1;
}else{
s[r]+=1;
}
}*/
}
signed main() {
io;
work();
return 0;
}
B.
B-阿宁的倍数_2023牛客寒假算法基础集训营6 (nowcoder.com)
思路:
预处理因数。有点集训营2的感觉。
处理出来数据范围内所有数的因子,在输入的时候根据处理出的数组索引去记录下标,询问时查找的就是当前数在an的倍数个数-在当前数的倍数个数。
#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
#define int ll
#define pb push_back
#define eb emplace_back
#define m_p make_pair
#define mod 998244353
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define inf 0x3f3f3f3f3f3f3f3f
const int N = 2e5 + 50;
int arr[2*N];
void work() {
int n,q;
cin>>n>>q;
vector<int>fac[N],id[N];
//令fac[n]储存n的所有因子
for(int i=1;i<N;++i){
for(int j=1;j*i<N;++j){
fac[i*j].pb(i);
}
}
//id[x]储存x的所有倍数的下标
for(int i=1;i<=n;++i){
scanf("%lld",&arr[i]);
for(auto x:fac[arr[i]]){
id[x].pb(i);
}
}
while(q--){
int op;int num;
scanf("%lld",&op);
if(op==1){
scanf("%lld",&arr[++n]);
for(auto y:fac[arr[n]]){
id[y].pb(n);
}
}else{
scanf("%lld",&num);
int tmp=upper_bound(id[arr[num]].begin(),id[arr[num]].end(),num)-id[arr[num]].begin();
int ans=id[arr[num]].size()-tmp;
printf("%lld\n",ans);
}
}
}
signed main() {
//io;
work();
return 0;
}
E.
E-阿宁的生成树_2023牛客寒假算法基础集训营6 (nowcoder.com)
思路:
小结论。(感觉不配用数论)
易知在k+1及之后的数和1取gcd时会有最小路径。
在1->k间暴力遍历找gcd,取最小,和与1的lcm(即当前值)比较取最小。
有关__gcd(),两个数据类型必须相同且是int or ll,浮点型不可,传过去什么值就传回来什么值。
#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
#define int ll
#define pb push_back
#define eb emplace_back
#define m_p make_pair
#define mod 998244353
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define inf 0x3f3f3f3f
const int N = 3e5 + 50;
//__builtin_ctzll(x);后导0的个数
//__builtin_popcount计算二进制中1的个数
void work() {
int n,k;cin>>n>>k;
int num=min(n,k+1);
int ans=n-num;
for(int i=2;i<=num;++i){
int minn=i;
//如果没有互素的数就和1取lcm最大为i
for(int j=i+1+k;j<=n;++j){
minn=min(minn,__gcd(i,j));
if(minn==1ll) break;
}
ans+=minn;
}
cout<<ans<<'\n';
}
signed main() {
io;
work();
return 0;
}
J.
J-阿宁指指点点_2023牛客寒假算法基础集训营6 (nowcoder.com)
思路:
小模拟题,有点读不懂(晕。
如果直接暴力模拟会t,优化需要做到把rank榜对的全部更新变成对某一个人的更新。打算过一阵子重新看题自己再写一写,有点不会。
#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
//#define int ll
#define pb push_back
#define eb emplace_back
#define m_p make_pair
#define mod 998244353
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define inf 0x3f3f3f3f3f3f3f3f
const int N = 2e4 + 50;
//__builtin_ctzll(x);后导0的个数
//__builtin_popcount计算二进制中1的个数
ll ans[N];
int tot=0;
map<string,int>mp;
vector<int> a[N],cha[N];//a记录做题时间,cha记录爬取时间
vector<ll> b[N];//记录前缀和
struct node{
int op,t;
string name;
int w,id;
friend bool operator <(node x,node y){
return x.t<y.t;
}
}q[N];
void work() {
int n,T,R;cin>>n>>T>>R;
for(int i=1;i<=n;++i){
cin>>q[i].op>>q[i].t>>q[i].name;
if(q[i].op==2){
cin>>q[i].w;
ans[i]=-1;
}
q[i].id=i;
if(!mp[q[i].name]) mp[q[i].name]=++tot;
}
sort(q+1,q+1+n);
for(int i=1;i<=n;++i){
int id=mp[q[i].name];//当前人
int t=q[i].t;//当前时间
if(q[i].op==1){
//找当前人被爬的最晚时间
int k=upper_bound(cha[id].begin(),cha[id].end(),t)-cha[id].begin()-1;
int time=t/T*T;
if(k>=0) time=max(time,cha[id][k]);//当前人rank榜最后更新时间
//找当前人做题最后时间
k=upper_bound(a[id].begin(),a[id].end(),time)-a[id].begin()-1;
ll sum=0;
//查到最大前缀和
if(k>=0) sum=b[id][k];
ans[q[i].id]=sum;
cha[id].pb(t+R);//在R时刻之后才可以更新
}else{
ll sum=q[i].w+(b[id].size()?b[id].back():0);
a[id].pb(t);
b[id].pb(sum);
}
}
for(int i=1;i<=n;++i){
if(ans[i]!=-1) cout<<ans[i]<<'\n';
}
}
signed main() {
io;
work();
return 0;
}
K.
K-阿宁大战小红_2023牛客寒假算法基础集训营6 (nowcoder.com)
思路:
是魔法一样的博弈啊,谢谢群友教我。
首先我们可以小范围暴力手玩博弈,然后去递推。
暴力注释写的很清楚了,可以画数轴帮助理解,后手必胜的递推也很显然。下面主要说说先手必胜的递推。
(*):以下1代表先手胜。
我们首先要知道2是不能连续的,因为如果i是后手必胜,i-1一定是先手必胜,先手可以+1让自己变成i状态的后手。
假设一个j是2,那么j-1 , j+1 , 2j , 2j+1一定都是1,那么我们现在看2j-1,他无论是加还是除都是1,所以他一定是先手必败态即2。现在我们看2j-2,他必是一个1。现在看j-1(1)就可递推出来了先手必胜的转移形式。
j-1 j j+1 2j-2 2j-1 2j 2j+1 1 2 1 1 2 1 1
#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
//#define int ll
#define pb push_back
#define eb emplace_back
#define m_p make_pair
#define mod 998244353
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define inf 0x3f3f3f3f3f3f3f3f
const int N = 3e5 + 50;
//__builtin_ctzll(x);后导0的个数
//__builtin_popcount计算二进制中1的个数
bool vis[N];
int f[N];
int x;
int dfs(int now,int who){
if(vis[now]) return (who==0)+1;
else if(now>=2*x) return 3;
//如果now比2x还要大就说明加过头了不能再除了就得一直加,平局
vis[now]=1;
int r1=dfs(now+1,who^1);
int r2=dfs(now/2,who^1);
vis[now]=0;
if(who==1){
if(r1==1||r2==1)return 1;
else if(r1==2&&r2==2)return 2;
else return 3;
}else{
if(r1==1&&r2==1)return 1;
else if(r1==2||r2==2) return 2;
else return 3;
}
//上面判断的大意是,如果当前人的一个操作可以使自己必胜那自己必胜
//如果每个操作都是对方胜那对方必胜
//否则无法分出胜负
}
void work() {
cin>>x;
mem(vis,0);
vis[0]=1;
for(int i=1;i<=40;++i){
f[i]=dfs(i,1);//dfs内: 1代表先手,0代表后手&&dfs的return值==fx
//f[x]: 1代表先手赢,2代表后手赢,3代表平局
}
for(int i=20;i<=500;++i){
if(f[i]==1){
//(*)
f[2*i]=1;f[2*i+1]=2;
}else if(f[i]==2){
f[2*i]=1;f[2*i+1]=1;
}
}
if(f[x]==1)cout<<"ning\n";
else if(f[x]==2)cout<<"red\n";
else cout<<"draw\n";
}
signed main() {
io;
work();
return 0;
}
L.
L-阿宁睡大觉_2023牛客寒假算法基础集训营6 (nowcoder.com)
思路:
容斥||dp,感觉本质类似。
容斥特性是奇数加偶数减。
这样写的像一个很容斥的dp啊。排序过后,我们先对每一个噩梦点求1,1到达的方案数,然后去递推,每两次遇到一个之前的点,-就会变成+(-(-))。这里f[i]表示的是当前噩梦格子是走过的第一个噩梦的所有方案数。
(有点抽象,举个例子,1是必经过1的路径数,2=2‘- (1->2),3=3'- (1->3) - (2->3)=3'- (1->3) - (2'->3 -(1->2->3))=3'- (1->3) - (2'->3) + (1->2->3)。大概酱紫吧。
最后再求出来从当前格子走到结尾的每种方法。
相当于我们把路径拆开了去计算。(感觉容斥也有点魔法的啊
另:注释掉的是快速幂求组合数的方法,线性逆元预处理快了不到十倍,但是不太懂为什么只能用多少处理多少,试着修改了2*n,3*n范围越大越不对。
----->2023.2.21更新:气乐了,是因为数组越界,我怎么总写愚蠢东西啊。
#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
#define int ll
#define pb push_back
#define eb emplace_back
#define m_p make_pair
#define mod 1000000007
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define fi first
#define se second
#define inf 0x3f3f3f3f3f3f3f3f
const int N = 3e5 + 50;
pii a[15];
ll fac[N],inv[N];
ll f[N];
int n,m;
ll C(int a,int b){
if(a<b or a<0 or b<0)
return 0;
return 1ll*fac[a]*inv[b]%mod*inv[a-b]%mod;
}
/*ll qpow(ll a, ll b = mod - 2, int p = mod) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % p;
a = a * a % p; b >>= 1;
}
return res;
}
int C(int n, int m) {
return fac[n] * qpow(fac[n - m] * fac[m] % mod) % mod;
}*/
void init(){
fac[0]=fac[1]=inv[0]=inv[1]=1;
//for (int i = 1; i <= 2 * n; i++) fac[i] = fac[i - 1] * i % MOD;
for(int i=2;i<=n;++i){
fac[i]=1ll*fac[i-1]*i%mod;
inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
}
for(int i=2;i<=n;++i){
inv[i]=1ll*inv[i]*inv[i-1]%mod;
}
}
void work() {
cin>>n>>m;
init();
for(int i=1;i<=m;++i){
cin>>a[i].fi>>a[i].se;
}
sort(a+1,a+1+m);
for(int i=1;i<=m;++i){
f[i]=C(a[i].fi+a[i].se-2,a[i].fi-1);
for(int j=1;j<i;++j){
if(a[j].fi<=a[i].fi&&a[j].se<=a[i].se){
f[i]=(f[i]-f[j]*C(a[i].fi-a[j].fi+a[i].se-a[j].se,a[i].fi-a[j].fi)%mod)%mod;
}
}
}
ll res=0;
for(int i=1;i<=n;++i){
int x=i,y=n-i+1;
res=(res+C(n-1,x-1))%mod;
for(int j=1;j<=m;++j){
if(a[j].fi<=x&&a[j].se<=y){
res=(res-f[j]*C(x-a[j].fi+y-a[j].se,x-a[j].fi)%mod)%mod;
}
}
}
res=(res+mod)%mod;
cout<<res<<'\n';
}
signed main() {
io;
work();
return 0;
}
拖了快两个周断断续续终于补完了这场,感觉期末有点寄,但需要复健一下力。