P9752 [CSP-S 2023] 密码锁

直接模拟统计就可以了,看每个状态有多少个转移的状态,就是输入的所有状态里面,把所以可能是由此转化来的++,最后循环所有的情况,如果能够转移的数量为n,那么就是结果++
#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
const int maxn=1e5+10;
int n,ans,dp[11][11][11][11][11];
int main()
{
//咋个就一开始没转过来呢
cin>>n;
for(int i=1;i<=n;i++){
int a,b,c,d,e;
cin>>a>>b>>c>>d>>e;
for(int j=1;j<=9;j++){
dp[(a+j)%10][b][c][d][e]++;
dp[a][(b+j)%10][c][d][e]++;
dp[a][b][(c+j)%10][d][e]++;
dp[a][b][c][(d+j)%10][e]++;
dp[a][b][c][d][(e+j)%10]++;
dp[(a+j)%10][(b+j)%10][c][d][e]++;
dp[a][(b+j)%10][(c+j)%10][d][e]++;
dp[a][b][(c+j)%10][(d+j)%10][e]++;
dp[a][b][c][(d+j)%10][(e+j)%10]++;
}
}
for(int i=0;i<=9;i++){
for(int j=0;j<=9;j++){
for(int k=0;k<=9;k++){
for(int t=0;t<=9;t++){
for(int p=0;p<=9;p++){
if(dp[i][j][k][t][p]==n) ans++;
}
}
}
}
}
cout<<ans<<endl;
return 0;
}
P9753 [CSP-S 2023] 消消乐

类似于kmp思想,记录跳转的地方,让fi表示以i结尾的合法区间个数,fi=fj+1,那么(j+1,i)是一个合法的区间
要保证最大。那么(j+1,i)是以i结尾的最短合法区间,这里就是可以直接跳转
#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
const int maxn=2e6+10;
//感觉有点kmp算法的思想
//记录跳转的地方,让fi表示以i结尾的合法区间个数,fi=fj+1,那么(j+1,i)是一个合法的区间
//要保证最大。那么(j+1,i)是以i结尾的最短合法区间
int dp[maxn] ,las[maxn];
int main()
{
int n;cin>>n;
string s;
cin>>s;
s='%'+s; //加个东西
LL ans=0;
for(int i=1;i<=n;i++){
for(int j=i-1;j>0;j=las[j]-1){
if(s[i]==s[j]){
las[i]=j;break;
}
}
if(las[i]) dp[i]=dp[las[i]-1]+1,ans+=dp[i];
}
cout<<ans<<endl;
return 0;
}
P9754 [CSP-S 2023] 结构体

大模拟,很多细节,结构体、指针的运用,仔细就可以,没特别复杂
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn=2e6+10;
//这个模拟比较难写,很多细节、结构体、指针很多应用
struct jiegou{
string name,type; //别名和类型
LL len,dp,py;
//长度、对齐、相对父亲的偏移
vector<jiegou *>son; //儿子(内涵的结构体)
jiegou(){ py=len=dp=0;name=type="";
}
jiegou(LL len,string tp){
this->py=0;this->len=len;this->dp=len;
this->type=tp;
}
};
map<string,jiegou> mp; //初始化结构体
LL js(LL a,LL b){
return a/b+int(a%b>0); //向上取整,计算偏移的时候需要
}
void build(string x,LL k){ //类型是x,里面有k个元素
jiegou tmp;
tmp.type=x;
LL py=0;
jiegou *las;
for(LL i=1;i<=k;i++){
string tpe,bieming;
cin>>tpe>>bieming;
jiegou *tmp1=new jiegou(mp[tpe]);
tmp1->name=bieming;
tmp.dp=max(tmp.dp,tmp1->dp); //对齐长度取长度最大的元素
if(i>1){
tmp1->py=tmp1->dp*js(las->py+las->len,tmp1->dp); //计算这个元素的起始位置
//就是这个元素的对齐长度乘以 上一个元素的偏移量加上长度除以这个元素的对齐长度并向上取整
}
tmp.son.push_back(tmp1);
las=tmp1;
}
tmp.len=tmp.dp*js(las->len+las->py,tmp.dp); //整个结构体的长度
mp[x]=tmp;
cout<<tmp.len<<" "<<tmp.dp<<endl; //输出结构体的长度和对齐
}
// 2 -> 加入内存
jiegou *tr=new jiegou(); //初识时没有初始化的结构体变量
void add(string tpe,string name){
jiegou *tmp=new jiegou(mp[tpe]);
tmp->name=name;
LL x,y,st=0;
vector<jiegou *> vec=tr->son; //一开始是空的!!现在创建一个加入一个
if(vec.empty()){
x=0;y=0;
}
else{
x=(*--vec.end())->py;
y=(*--vec.end())->len;
}
st=js(x+y,tmp->dp)*tmp->dp; //偏移值
tmp->py=st; //这个元素的偏移
tr->son.push_back(tmp);
cout<<st<<endl;
}
//3 -->直接暴力分割出来每一层索引的名字然后暴力一层一层跳就可以了
LL findd(string x){
vector<string> vec;
LL las=0,len=x.length();
for(LL i=1;i<=len;i++){
if(x[i-1]=='.') vec.push_back(x.substr(las,i-las-1)),las=i;
//一层层放进去
}
vec.push_back(x.substr(las,len-las));
jiegou *now=tr;
LL st=0,py;
for(LL i=1;i<=vec.size();i++){
py=st;
for(int j=1;j<=now->son.size();j++){
jiegou *k=now->son[j-1];
py=st+k->py;
if(k->name==vec[i-1]){
st=py;
now=k; //这个也在往里走,往里面搜索每一个元素
break;
}
}
}
return py;
}
// 4 -->递归找一下,暴力一层层跳,递归存一下目前的总偏移量,如果子节点包含这个区间就往下找
string getb(jiegou *now,LL st,LL tar){
string ans="";
for(LL i=1;i<=now->son.size();i++){
jiegou *k=now->son[i-1];
if(st+(k->py)<=tar&&tar<st+(k->py)+(k->len)){ //在这个结构体里面
ans=k->name;
if(k->son.size()) ans+="."+getb(k,st+(k->py),tar);
break;
}
}
if(ans.empty()) return "ERR"; //如果要返回err,实际上只有最后一层是err,因为有可能在一个结构体里面,知只是没有被占据
else return ans;
}
int main()
{
LL n;
cin>>n;
mp["long"]=jiegou(8ll,"long");
mp["int"]=jiegou(4ll,"int");
mp["short"]=jiegou(2ll,"short");
mp["byte"]=jiegou(1ll,"byte");
for(LL i=1;i<=n;i++){
int opt;
cin>>opt;
if(opt==1){
string x;LL y;
cin>>x>>y;
build(x,y);
}
else if(opt==2){
string x,y;
cin>>x>>y;
add(x,y);
}
else if(opt==3){
string x;cin>>x;
cout<<findd(x)<<endl;
}
else if(opt==4){
LL adr;cin>>adr;
string ans=getb(tr,0,adr);
if(ans.find("ERR")!=-1) cout<<"ERR"<<endl;
else cout<<ans<<endl;
}
}
return 0;
}
P9755 [CSP-S 2023] 种树

虽然知道有单调性 但是要写出二分还是比较难 --- 二层二分
https://www.luogu.com.cn/blog/979266/p9755-csp-s-2023-zhong-shu
写的比较好,首先因为bi+cix 这个是单调的所以可以从这里入手二分(区分什么时候取bi+cix什么时候取1),我们可以对于每一个地块i,求出最晚种树且到 x天时能到达 ai的天数ki
对于每个点i可以在1——ki之间任意一个时间种树,每个时间只能种一棵树,球有没有满足的方案
贪心做法:将ki从小到大排序,然后按照树的结构去判断是否有这样的方案(暴力枚举每个点到父亲的路上是否中了树)并且这个时间是否超过ki
开__int128
#include <bits/stdc++.h>
using namespace std;
typedef __int128 LL;
const int maxn=1e5+100;
const int INF=1e10;
//。虽然知道有单调性 但是要写出二分还是比较难 --- 二层二分
//https://www.luogu.com.cn/blog/979266/p9755-csp-s-2023-zhong-shu 写的比较好
//首先因为bi+cix 这个是单调的所以可以从这里入手二分(区分什么时候取bi+cix什么时候取1),我们可以对于每一个地块i,求出最晚种树且到 x天时能到达 ai的天数ki
//对于每个点i可以在1——ki之间任意一个时间种树,每个时间只能种一棵树,球有没有满足的方案
//贪心做法:将ki从小到大排序,然后按照树的结构去判断是否有这样的方案(暴力枚举每个点到父亲的路上是否中了树)并且这个时间是否超过ki
//开__int128
inline LL read(){
LL x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(LL x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
struct node{
LL x,y; //表示最晚开始的天数,节点标号
bool operator < (const node &yyy)const{
return x<yyy.x;
}
}k[maxn];
LL n;
LL a[maxn],b[maxn],c[maxn],h[maxn],p[maxn],fa[maxn];
//h数组就是每个节点的最晚种树节点
bool vis[maxn];
vector<LL> e[maxn]; //树
void adde(LL u,LL v){
e[u].push_back(v);
e[v].push_back(u);
}
void dfs(LL u,LL f){
for(int i=0;i<e[u].size();i++){
LL op=e[u][i];
if(op==f) continue;
fa[op]=u;
dfs(op,u);
}
}
LL js(LL i,LL l,LL r){ //计算第i课树,从l到r天的生长总长度
LL t=r-l+1;
if(h[i]<l) return t;
if(h[i]>r) return t*b[i]+(((l+r)*t)/2)*c[i]; //只有前半部分
return (r-h[i])+(h[i]-l+1)*b[i]+(((l+h[i])*(h[i]-l+1))/2)*c[i];
}
bool check(LL x){
for(int i=1;i<=n;i++){
if(js(i,1,x)<a[i]) return 0; //如果最多x天,那么就算是从第一天开始也不行,说明肯定不是合法的方案
LL l=1,r=n; //看从第几个开始种树
while(l<r){
LL mid=(l+r+1)>>1;
if(js(i,mid,x)>=a[i]) l=mid;
else r=mid-1;
}
k[i]={l,i};
p[i]=k[i].x; //最晚开始的时间 要多余记录这个,因为后面要比较
}
memset(vis,0,sizeof(vis));
sort(k+1,k+1+n);
vis[0]=1;
LL ttt=0;
for(int i=1;i<=n;i++){
stack<LL> d;
LL t=k[i].y;
while(!vis[t]){
d.push(t);
vis[d.top()]=1;
t=fa[t]; //往上走 因为肯定这些没有被种
}
while(!d.empty()){
++ttt;
if(p[d.top()]<ttt) return 0; //如果这个时间开始满足在最晚开始时间之前
d.pop();
}
}
return 1;
}
int main(){
// scanf("%lld",&n);
// for(int i=1;i<=n;i++) scanf("%lld %lld %lld",&a[i],&b[i],&c[i]);
// for(LL u,v,i=1;i<=n-1;i++){
// scanf("%lld %lld",&u,&v);adde(u,v);
// }
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
b[i]=read();
c[i]=read();
}
for(int u,v,i=1;i<n;i++){
u=read(),v=read();
adde(u,v);
}
for(int i=1;i<=n;i++){
if(c[i]>=0) h[i]=INF;
else h[i]=(1-b[i])/c[i];
}
dfs(1,1);
LL l=n,r=1e9; //l起始值为n
while(l<r){
LL mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
write(l);
return 0;
}
posted on
浙公网安备 33010602011771号