T1
直接 \(10^{5}\) 枚举状态就过了,合法的非零差分数量只可能为 \(1,2\)(\(0\) 相当于没转,按照题意 “都不是正确密码” 是不符的)
需要注意的是形如 0 9 1 1 1 -> 1 0 1 1 1
这样的合法状态
#include<bits/stdc++.h>
using namespace std;
int n;
int a[10][9];
int p[6];
bool check(int id){
int r[6];
int cnt=0;
for(int i=1;i<=5;++i){
r[i]=a[id][i]-p[i];
while(r[i]<0) r[i]+=10;
}
for(int i=1;i<=5;++i){
if(r[i]!=0){
cnt++;
}
}
/*
1 9
9 7
8 -2
8 6
7 -3
*/
if(cnt==1){
return true;
}
else if(cnt==2){
for(int i=1;i<=4;++i){
if(r[i]!=0 and r[i+1]==r[i]){
return true;
}
}
return false;
}
return false;
}
int main(){
//freopen("lock.in","r",stdin);
//freopen("lock.out","w",stdout);
cin>>n;
for(int i=1;i<=n;++i){
for(int j=1;j<=5;++j){
cin>>a[i][j];
}
}
int ans=0;
for(p[1]=0;p[1]<=9;++p[1]){
for(p[2]=0;p[2]<=9;++p[2]){
for(p[3]=0;p[3]<=9;++p[3]){
for(p[4]=0;p[4]<=9;++p[4]){
for(p[5]=0;p[5]<=9;++p[5]){
bool can=true;
for(int i=1;i<=n;++i){
if(!check(i)){
can=false;
break;
}
}
if(can) ans++;
}
}
}
}
}
// cout<<cnt1<<" "<<cnt2<<endl;
cout<<ans<<endl;
}
T2
首先能想到一个 \(O(n)\) 的 check(),就是开一个栈遍历,入栈时判断栈顶元素与放入元素能不能消,能消就消掉,最后判断栈是否非空
由此想到 \(n^{2}\) 做法,枚举开头,做 \(n\) 次 check,每当栈空就统计一次答案
由此想到 \(n\log n\) 做法,考虑只对整体 check() 一次,假如 \(i\neq j\),但 \(i,j\) 处栈的状态相同,那么就可以知道 \(i,j\) 之间的元素一定是可消除的,推广,假设有 \(k\) 个栈状态相同,对答案的贡献就是 \(\frac{k(k-1)}{2}\)
因此想到哈希,但是我一开始用的是异或哈希只有 20pts,想了一下发现异或哈希有交换律,会被 abab
这样的数据卡掉
直接普通哈希即可. 我看到题解区还有矩阵乘法的构造方法,总之选择的哈希算法无交换律就行
然后因为每次计算哈希值都从头计算,导致有一个 \(n^{2}\log n\) 的神奇复杂度过了 90pts,然后被随机数据卡了(因为随机数据的匹配值太小,导致栈里元素总是多的,会拉高复杂度)
实际上可以这么转移:
- 栈空 \(h_{i}=s_{i}\)
- 配对 \(h_{i}=h_{lst_{top}}\),\(lst_{top}\) 是栈顶元素的前一个元素
- 未匹配,\(h_{i}=h_{top}*num+s_{i}\),注意这里应该是 \(h_{top}\) 而不是 \(h_{i-1}\),因为上一个元素可能被弹出去了
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
template<typename T>
void read(T& x){
x=0;bool sym=0;char c=getchar();
while(!isdigit(c)){sym^=(c=='-');c=getchar();}
while(isdigit(c)){x=x*10+c-48;c=getchar();}
if(sym)x=-x;
}
template<typename T,typename... Args>
void read(T& x,Args&... args){
read(x);read(args...);
}
int n;
string s;
inline unsigned long long _hash(stack<long long> st){
unsigned long long res=0;
while(!st.empty()){
res=res*233ull+st.top();
st.pop();
}
return res;
}
struct node{
char num;
int pla;
};
stack<node>st;
unordered_map<unsigned long long,long long>mp;
unsigned long long __hash[2000001];
int main(){
// freopen("P9753_11.in","r",stdin);
cin>>n>>s;
s='?'+s;
mp[0]++;
__hash[0]=0;
for(int i=1;i<=n;++i){
if(st.empty()){
st.push({s[i],i});
__hash[i]=s[i];
mp[__hash[i]]++;
}
else if(st.top().num==s[i]){
__hash[i]=__hash[st.top().pla-1];
st.pop();
mp[__hash[i]]++;
}
else{
__hash[i]=(__hash[st.top().pla]*233ull+s[i]);
st.push({s[i],i});
mp[__hash[i]]++;
}
// cout<<__hash[i]<<endl;
}
long long ans=0;
for(auto i:mp){
// cout<<i.second<<endl;
ans+=((i.second)*(i.second-1))/2;
}
cout<<ans<<endl;
}
T3
他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟他妈的谁放的大模拟
- 末端 \(addr=\) 首位 \(addr+size\large{-1}\),5pts
- 考虑没声明就问你的情况,这样的情况会在操作 \(4\) 中出现,15pts
- 注意结构体的对齐,不是根据 \(totsize\),而是 \(\max\{subsize\}\),25pts
- 结构体内部元素是按照内部元素对齐方式对齐,而不是按照结构体对齐方式对齐,也就是 \(totsize\) 可能并不等于 \(k\times \max\{subsize\}\),65pts
- 一些奇奇怪怪的变量问题,100pts
耗费了下午一+下午二+晚新闻+晚一+晚二+晚三/2=250min
因为这个模拟比较小所以没写注释,你们不要学这种坏习惯,否则有概率导致忘掉自己写的是什么导致需要重新打
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define type_byte 1
#define type_short 2
#define type_int 4
#define type_long 8
#define type_stru 9
ofstream cth;
struct stru{
map<string,int>mem_id;
map<int,string>mem_name;
vector<int>mem_type;
vector<int>mem_size;
map<int,int>str_mem_id;
vector<int>mem_addr;
int cnt=-1;
int maxsize,totsize,totaddr=0;
};
vector<stru>str;
vector<int>address;
map<string,int>str_id;
int now_address=0;
int cnt=-1,strcnt=-1;
vector<bool>isstr;
map<string,int>id;
map<int,string>name;
vector<int>str_reflect_id;
vector<int>sizeall;
int add_new(string _name,int size,bool _isstr,int reflect_id){
if(_isstr) while(now_address%str[reflect_id].maxsize!=0) now_address++;
else while(now_address%size!=0) now_address++;
id[_name]=++cnt;
name[cnt]=_name;
address.push_back(now_address);
int res=now_address;
now_address+=size;
isstr.push_back(_isstr);
str_reflect_id.push_back(reflect_id);
sizeall.push_back(size);
return res;
}
namespace operation1{
int mem_add_new(int strid,int size,int _isstr,int totsize){
// if(str[strid].totaddr!=0) str[strid].totaddr++;
while(str[strid].totaddr%size!=0) str[strid].totaddr++;
// cth<<"[struct] new var from "<<str[strid].totaddr<<endl;//" to "<<str[strid].totaddr+totsize-1<<endl;
int res=str[strid].totaddr;
str[strid].totaddr+=totsize;
return res;
}
void fixed_size(int strid,int masxsize){
while(str[strid].totaddr%masxsize!=0) str[strid].totaddr++;
}
void act(){
int k;string name;
cin>>name>>k;
// cth<<"new struct "<<name<<" ["<<k<<"]"<<endl;
str.push_back({});strcnt++;
str_id[name]=strcnt;
for(int i=1;i<=k;++i){
string type_name,_name;
cin>>type_name>>_name;
str[strcnt].mem_id[_name]=++str[strcnt].cnt;
str[strcnt].mem_name[str[strcnt].cnt]=_name;
// cth<<"["<<type_name<<"]";
if(type_name=="byte"){
str[strcnt].mem_type.push_back(type_byte);
str[strcnt].mem_size.push_back(type_byte);
str[strcnt].mem_addr.push_back(mem_add_new(strcnt,type_byte,false,type_byte));
}
else if(type_name=="short"){
str[strcnt].mem_type.push_back(type_short);
str[strcnt].mem_size.push_back(type_short);
str[strcnt].mem_addr.push_back(mem_add_new(strcnt,type_short,false,type_short));
}
else if(type_name=="int"){
str[strcnt].mem_type.push_back(type_int);
str[strcnt].mem_size.push_back(type_int);
str[strcnt].mem_addr.push_back(mem_add_new(strcnt,type_int,false,type_int));
}
else if(type_name=="long"){
str[strcnt].mem_type.push_back(type_long);
str[strcnt].mem_size.push_back(type_long);
str[strcnt].mem_addr.push_back(mem_add_new(strcnt,type_long,false,type_long));
}
else{
str[strcnt].mem_type.push_back(type_stru);
str[strcnt].mem_size.push_back(str[str_id[type_name]].maxsize);
str[strcnt].str_mem_id[i-1]=str_id[type_name];
str[strcnt].mem_addr.push_back(mem_add_new(strcnt,str[str_id[type_name]].maxsize,true,str[str_id[type_name]].totsize));
}
str[strcnt].maxsize=max(str[strcnt].maxsize,str[strcnt].mem_size.back());
}
fixed_size(strcnt,str[strcnt].maxsize);
str[strcnt].totsize=str[strcnt].totaddr;
cout<<str[strcnt].totsize<<" "<<str[strcnt].maxsize<<endl;
// cth<<"struct end: totsize["<<str[strcnt].totsize<<"]"<<endl;
}
}
namespace operation2{
void act(){
string type_name,_name;
cin>>type_name>>_name;
if(type_name=="byte"){
cout<<add_new(_name,type_byte,false,-1)<<endl;
}
else if(type_name=="short"){
cout<<add_new(_name,type_short,false,-1)<<endl;
}
else if(type_name=="int"){
cout<<add_new(_name,type_int,false,-1)<<endl;
}
else if(type_name=="long"){
cout<<add_new(_name,type_long,false,-1)<<endl;
}
else{
// cout<<"gogogogogo "<<_name<<" "<<str_id[type_name]<<endl;
cout<<add_new(_name,str[str_id[type_name]].totsize,true,str_id[type_name])<<endl;
}
// cth<<"[struct] new var from "<<address[cnt]<<endl;
//cth<<"new var "<<type_name<<" '"<<_name<<"' in address "<<address[cnt]<<" to "<<address[cnt]+sizeall[cnt]-1<<endl;
}
}
namespace operation3{
int judge_remain(int strid,string remain){
// cout<<"judge remain "<<" "<<strid<<" "<<remain<<endl;
if(remain.empty()) return 0;
int i=0;string nam,rem;
for(i=0;i<=(int)remain.length()-1;++i){
if(remain[i]=='.'){
break;
}
nam.push_back(remain[i]);
}
for(i++;i<=(int)remain.length()-1;++i){
rem.push_back(remain[i]);
}
// cout<<"tyope ";
// for(int i:str[strid].mem_type) cout<<i<<" ";
// cout<<endl;
if(str[strid].mem_type[str[strid].mem_id[nam]]!=type_stru){
// cout<<"yes "<<nam<<endl;
return str[strid].mem_addr[str[strid].mem_id[nam]];
}
else{
return str[strid].mem_addr[str[strid].mem_id[nam]]+judge_remain(str[strid].str_mem_id[str[strid].mem_id[nam]],rem);
}
}
void act(){
string x;
cin>>x;
int i=0;string nam,rem;bool hasdot=false;
for(i=0;i<=(int)x.length()-1;++i){
if(x[i]=='.'){
hasdot=true;
break;
}
nam.push_back(x[i]);
}
for(i++;i<=(int)x.length()-1;++i){
rem.push_back(x[i]);
}
int res=0;
// cout<<"judge "<<nam<<" "<<rem<<endl;
if(hasdot){
// cth<<"JUDGE ADDRESS "<<x<<endl;
// cout<<" ------"<<id[nam]<<" "<<str_reflect_id[id[nam]]<<endl;
cout<<(res=address[id[nam]]+judge_remain(str_reflect_id[id[nam]],rem))<<endl;
// cth<<"JUDGE END: "<<res<<endl;
}
else{
// cth<<"JUDGE ADDRESS "<<x<<endl;
cout<<(res=address[id[nam]])<<endl;
// cth<<"JUDGE END: "<<res<<endl;
}
}
}
namespace operation4{
string judge_remain(int strid,int remain){
// cth<<"JUDGE REMAIN-----"<<strid<<" "<<remain<<endl;
// if(str[strid].cnt==-1) return "";
int _id=0;
str[strid].mem_addr.push_back(1e18);
for(_id=0;_id<=str[strid].cnt;++_id){
if(remain>=str[strid].mem_addr[_id] and remain<str[strid].mem_addr[_id+1]) break;
}
// cth<<"[[[[[find "<<_id<<" "<<str[strid].mem_addr[_id]<<" "<<str[strid].mem_addr[_id]+str[strid].mem_size[_id]-1<<endl;
// cth<<"judge remain ::::: "<<strid<<" "<<remain<<endl;
if(str[strid].mem_type[_id]!=type_stru){
if(str[strid].mem_addr[_id]<=remain and str[strid].mem_addr[_id]+str[strid].mem_size[_id]-1>=remain);
else{
// cth<<"Error in "<<strid<<" when remain "<<remain<<" : find "<<_id<<" ["<<str[strid].mem_addr[_id]<<","<<str[strid].mem_addr[_id]+str[strid].mem_size[_id]-1<<"]"<<endl;
return "";
}
// if(remain%str[strid].maxsize!=0) return "";
return str[strid].mem_name[_id];
}
else{
string t=judge_remain(str[strid].str_mem_id[_id],remain-str[strid].mem_addr[_id]);
if(t.empty()) return "";
return (str[strid].mem_name[_id]+"."+t);
}
str[strid].mem_addr.pop_back();
}
void act(){
int addr;
cin>>addr;
// cth<<"JUDGE-------- "<<addr<<endl;
if(address.empty()){
cout<<"ERR"<<endl;
return;
}
address.push_back(1e18);
int _id=0;
for(_id=0;_id<=cnt;++_id){
if(address[_id]<=addr and address[_id+1]>addr) break;
}
// cout<<"id-----"<<_id<<endl;
if(isstr[_id]==false){
if(addr<address[_id] or addr>address[_id]+sizeall[_id]-1){
cout<<"ERR"<<endl;
}
else{
cout<<name[_id]<<endl;
}
}
else{
// cth<<"into[ "<<address[_id]<<" "<<str[str_reflect_id[_id]].totsize<<endl;
string t=judge_remain(str_reflect_id[_id],addr-address[_id]);
if(t.empty()) cout<<"ERR"<<endl;
else cout<<(name[_id]+"."+t)<<endl;
}
address.pop_back();
}
}
/*
0 1
*/
int ops;
signed main(){
// cth.open("CON");
// #ifdef ONLINE_JUDGE
// freopen("struct.in","r",stdin);
// freopen("struct.out","w",stdout);
// #else
// freopen("y3.in","r",stdin);
// freopen("out.out","w",stdout);
// #endif
cin>>ops;
int op;
while(ops--){
cin>>op;
if(op==1){
// cout<<"st act 1"<<endl;
operation1::act();
// cout<<"ed act 1"<<endl;
}
if(op==2){
// cout<<"st act 2"<<endl;
operation2::act();
// cout<<"ed act 2"<<endl;
}
if(op==3){
// cout<<"st act 3"<<endl;
operation3::act();
// cout<<"ed act 3"<<endl;
}
if(op==4){
// cout<<"st act 4"<<endl;
operation4::act();
// cout<<"ed act 4"<<endl;
}
}
}
T4
看到给了答案范围以及答案具有单调性,基本就是二分答案了
然而这道题二分答案不是太好写,有两个需要解决的. 显然我们应该有一个函数来求 “点 \(i\) 至少需要在第 \(d_{i}\) 天放下去,否则就到达不了预定高度” 中的 \(d_{i}\),考虑到 \(n\) 不是很卡,因此直接二分答案,写个二分套二分,但是显然里面还需要一个函数来求 “对给定的 \(a,b\) 和区间 \([l,r]\) 的树的高度”,这里需要我们推个简单式子
显然,当 \(c_{i}\gt 0\) 的时候,由于 \(b_{i}\ge 1\),所以直接求即可
否则,我们应该找出令 \(c_{i}x+b_{i}=0\) 的 \(x\),对左右两边求分段函数
这里需要注意的是,因为这里的 \(x\) 应该是整数,但是对该方程的计算结果不一定是整数,所以要处理一下取整问题
然后就可以 check 了,考虑怎么 check,一个容易想到的贪心思路是我们应该对节点的 \(d_{i}\) 从小到大排序,考虑到最小的 \(d_{i}\) 一定要优先求,因此每次都从当前 \(d_{i}\) 最小的 \(i\) 搜到根节点,沿途未种树的节点加起来和时间戳比对即可
被卡常的一个大幅度优化
设点 \(i\) 至少需要在第 \(d_{i}\) 天放下去,如果需要的优化幅度不是非常大(\(300ms\) 以内),那么直接判断是否存在 \(d_{i}=1 \operatorname{and} i\neq 1\) 即可
否则,维护每个节点的深度,那么当存在 \(d_{i}\lt deep_{i}\) 的时候就可以返回了
注意开 int128
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
template<typename T>
void read(T& x){
x=0;bool sym=0;char c=getchar();
while(!isdigit(c)){sym^=(c=='-');c=getchar();}
while(isdigit(c)){x=x*10+c-48;c=getchar();}
if(sym)x=-x;
}
template<typename T,typename... Args>
void read(T& x,Args&... args){
read(x);read(args...);
}
int n;
struct area{
int a,b,c;
__int128 tot_days;
}a[100001];
inline __int128 calc(__int128 a,__int128 b,__int128 c,__int128 l,__int128 r){
if(c>=0) return (r-l+1)*b+(r-l+1)*(l+r)/2*c;
__int128 x=(1-b)/c;
if(c<0) x=min(x,r);
if(x<l) return r-l+1;
if(x>r) return (r-l+1)*b+(r-l+1)*(l+r)/2*c;
return (x-l+1)*b+(x-l+1)*(l+x)/2*c+r-x;
}
inline int cal_days(__int128 a,__int128 b,__int128 c,__int128 mid){
//firstly cal the min x make the b+cx>=1
//that if c>0 that cx>=1-b x>=(1-b)/c
// if c<0 that cx>=1-b x<=(1-b)/c
// if(c==0){
//always the same
// return mid-ceil(a*1.0/max(1ll,b));
// }
if(calc(a,b,c,1,mid)<a) return false;
int l=0,r=n,res=-2;
while(l<=r){
int _mid=(l+r)/2;
if(calc(a,b,c,_mid,mid)>=a){
l=_mid+1;
res=_mid;
}
else{
r=_mid-1;
}
}
return res;
// if(c>0){
//
// }
// if(c<0){
//
// }
}
vector<int>e[100001];
int fa[100001];
void dfs(int now,int last){
fa[now]=last;
for(int i:e[now]){
if(i!=last){
dfs(i,now);
}
}
}
int p[100001];
bool vis[100001]={true};
int stk[100001];
inline bool judge(){
memset(vis,0,sizeof vis);vis[0]=true;
for(int i=1;i<=n;++i){
p[i]=i;
}
sort(p+1,p+n+1,[](int x,int y){return a[x].tot_days<a[y].tot_days;});
int times=0;
for(int i=1;i<=n;i++){
int now=p[i];
stack<int>st;
while(vis[now]==false and now!=0){
st.push(now);
vis[now]=true;
now=fa[now];
}
if(!st.empty() and st.top()==0) st.pop();
while(!st.empty()){
if(a[st.top()].tot_days<++times){
// cout<<"falsein "<<st.top()<<" "<<a[st.top()].tot_days<<" "<<times<<endl;
return false;
}
st.pop();
}
}
// cout<<"acc"<<endl;
return true;
}
inline bool check(int mid){
// cout<<"checkin "<<mid<<endl;
for(int i=1;i<=n;++i){
a[i].tot_days=cal_days(a[i].a,a[i].b,a[i].c,mid);
// a[i].tot_days=mid-a[i].tot_days;
// cout<<a[i].tot_days<<" ";
if(a[i].tot_days<0 or (a[i].tot_days==1 and i!=1)){
// cout<<"falseout "<<endl;
return false;
}
}
// cout<<endl;
return judge();
}
/*
4 2 4 2
*/
signed main(){
// freopen("tree.in","r",stdin);
// freopen("tree.out","w",stdout);
// freopen("tree2.in","r",stdin);
// freopen("out.out","w",stdout);
read(n);
for(int i=1;i<=n;++i){
read(a[i].a,a[i].b,a[i].c);
}
for(int i=1;i<=n-1;++i){
int x,y;
read(x,y);
e[x].push_back(y);
e[y].push_back(x);
}
dfs(1,0);
int l=0,r=1e9,ans=-1;
while(l<=r){
// cout<<"check "<<l<<" "<<r<<endl;
int mid=(l+r)/2;
if(check(mid)){
r=mid-1;
ans=mid;
}
else{
l=mid+1;
}
}
cout<<ans<<endl;
}
标签:__,name,int,2023,他妈的,now,CSP,模拟
From: https://www.cnblogs.com/HaneDaCafe/p/18407007