6.29集训--集训模拟赛3
总结
今天集齐了四种颜色
这一次真是水翻了,除去第一题送分题,后三道题只拿了50分
开考后完全不在状态,最后的一个半小时一点代码都没有写出来
A、李时珍的皮肤衣
分析
\(n\)的数据最大达到了\(10^{10}\),显然是一道结论题
枚举几组样例可以发现,最终的答案为\(2^{n-1}+1\)对\(n\)取模
其实就是相当于二进制下的进位
因为\(n\)很大,所以要用快速幂
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
ll ksm(ll now,ll fa){
ll xz=now;
ll ans=1;
while(fa){
if(fa&1){
ans*=xz;
ans=ans%n;
}
fa=(fa>>1);
xz=xz*xz%n;
}
return ans%n;
}
int main(){
scanf("%lld",&n);
printf("%lld\n",(ksm(2,n-1)+1)%n);
return 0;
}
B、马大嘴的废话
分析
如果直接暴力枚举的话可以得到60分
然而暴力写挂了
这道题的最优解要用到AC自动机,但是AC自动机并没有学
林大佬用哈希表过了这道题,但模数比较难取,而且不用c++11会T
其实这一道题可以用Tire树维护
60代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=20005;
char s[maxn][25];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s[i]);
}
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++){
char a[25];
scanf("%s",a);
int ans=0;
int now=strlen(a);
int be=0;
for(int j=1;j<=n;j++){
if(strstr(s[j],a)!=NULL) ans++;
}
printf("%d\n",ans);
}
return 0;
}
哈希表代码(林大佬)
#include<cstdio>
#include<algorithm>
#include<unordered_map>
#include<string>
#include<cstring>
#include<vector>
using namespace std;
#define ll long long
const ll mod1=2e17+19260817;
const int maxch=43;
const int maxn=2e1+1;
unordered_map<ll,int> mapp1;
vector<ll> s1;
unordered_map<ll,bool> vis1;
char a[maxn];
int n;
void solve1(int l,int r)
{
ll ans=0,now=1ll;
for(int i=l;i<=r;i++)
{
ans+=now*(a[i]-'a'+1)%mod1,ans%=mod1;
now*=(ll)maxch,now%=mod1;
}
if(vis1[ans]) return;
else vis1[ans]=1,s1.push_back(ans),mapp1[ans]++;
}
int calc1()
{
ll ans=0,now=1ll;
for(int i=0;i<n;i++)
{
ans+=now*(a[i]-'a'+1)%mod1,ans%=mod1;
now*=(ll)maxch,now%=mod1;
}
return mapp1[ans];
}
int main()
{
int m;
scanf("%d",&n);
while(n--)
{
scanf("%s",a);
m=strlen(a);
for(int i=0;i<m;i++)
for(int j=i;j<m;j++)
solve1(i,j);
for(int i=0;i<s1.size();i++) vis1[s1[i]]=0;
s1.clear();
}
scanf("%d",&m);
while(m--)
{
scanf("%s",a);
n=strlen(a);
printf("%d\n",calc1());
}
return 0;
}
Tire树代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
int tire[maxn][26],mark[maxn][26],cnt[maxn][26];
int n,m;
int tot=0;
char s[30];
char a[30];
void insert(int l,int r,int id){
int now=0;
int t;
for(int i=l;i<=r;i++){
t=s[i]-'a';
if(tire[now][t]){
if(id!=mark[now][t]){
cnt[now][t]++;
mark[now][t]=id;
}
}
else {
tire[now][t]=++tot;
mark[now][t]=id;
cnt[now][t]=1;
}
now=tire[now][t];
}
}
int query(char a[]){
int len=strlen(a);
int now=0,ans=0;
for(int i=0;i<len;i++){
int t=a[i]-'a';
if(tire[now][t]==0)return 0;
ans=cnt[now][t];
now=tire[now][t];
}
return ans;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>s;
int len=strlen(s);
for(int j=0;j<len;j++){
insert(j,len-1,i);
}
}
cin>>m;
for(int i=1;i<=m;i++){
cin>>a;
cout<<query(a)<<'\n';
}
return 0;
}
C、SSY的队列
分析
这道题的正解要用哈希表,所以先讲一下部分分的解法
首先就是最简单的暴力枚举,求全排列,每次求出来之后判断是否合法,预计得分二十分
还有一种七十分的状压DP解法
我们设\(f[i][j]\)为当前排好队的人的状态为\(i\),并且队伍末尾的人为\(j\)时的方案数
所以有\(f[i][j]+=f[i^(1<<(j-1))][k];\)
其中\(abs(a[j]-a[k])%m!=0\)
\(i\&(1<<(j-1))!=0\)
\(i\&(1<<(k-1))!=0\)
20分暴力
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1234567891;
const int maxn=35;
ll a[maxn];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
ll m;
scanf("%lld",&m);
sort(a+1,a+1+n);
ll ans=0;
while(1){
bool jud=0;
for(int i=1;i<n;i++){
if(abs(a[i]-a[i+1])%m==0){
jud=1;
break;
}
}
if(jud==0) ans++;
if(next_permutation(a+1,a+n+1)==0) break;
}
printf("%lld\n",ans%mod);
return 0;
}
70分状压
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=23;
const ll mod=1234567891;
ll f[1<<maxn][maxn],a[maxn];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
f[1<<(i-1)][i]=1;
}
ll m;
scanf("%lld",&m);
int mmax=(1<<n)-1;
for(int i=0;i<=mmax;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
if(abs(a[j]-a[k])%m==0 || (i&(1<<(j-1))==0) || (i&(1<<(k-1))==0)) continue;
f[i][j]+=f[i^(1<<(j-1))][k];
f[i][j]%=mod;
}
}
}
ll ans=0;
for(int i=1;i<=n;i++){
ans+=f[mmax][i];
ans%=mod;
}
printf("%lld\n",ans);
return 0;
}
D、清理牛棚
分析
这道题的解法很多,有线性DP、线段树优化DP、单调栈优化DP、最短路
最短路解法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6+5;
struct asd{
int from,to,next;
ll val;
}b[maxn];
int head[maxn],tot=1;
void ad(int aa,int bb,ll cc){
b[tot].from=aa;
b[tot].to=bb;
b[tot].val=cc;
b[tot].next=head[aa];
head[aa]=tot++;
}
struct jie{
int num;
ll jl;
jie(int aa=0,ll bb=0){
num=aa,jl=bb;
}
bool operator < (const jie& A) const{
return jl>A.jl;
}
};
ll dis[maxn];
bool vis[maxn];
priority_queue<jie> q;
void dij(int xx){
memset(dis,0x3f,sizeof(dis));
dis[xx]=0;
q.push(jie(xx,0));
while(!q.empty()){
int now=q.top().num;
q.pop();
if(vis[now]) continue;
vis[now]=1;
for(int i=head[now];i!=-1;i=b[i].next){
int u=b[i].to;
if(dis[u]>dis[now]+b[i].val){
dis[u]=dis[now]+b[i].val;
q.push(jie(u,dis[u]));
}
}
}
}
int main(){
memset(head,-1,sizeof(head));
int n,m,e;
scanf("%d%d%d",&n,&m,&e);
for(int i=1;i<=n;i++){
int aa,bb;
ll cc;
scanf("%d%d%lld",&aa,&bb,&cc);
ad(aa,bb+1,cc);
}
for(int i=m;i<e;i++){
ad(i+1,i,0);
}
dij(m);
if(dis[e+1]==0x3f3f3f3f3f3f3f3f){
printf("-1\n");
return 0;
}
printf("%lld\n",dis[e+1]);
return 0;
}
线性DP解法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100005;
ll f[maxn];
struct asd{
int l,r;
ll hd;
}b[maxn];
bool cmp(asd aa,asd bb){
if(aa.r==bb.r) return aa.l<bb.l;
return aa.r<bb.r;
}
int main(){
memset(f,0x3f,sizeof(f));
int n,m,e;
scanf("%d%d%d",&n,&m,&e);
for(int i=1;i<=n;i++){
scanf("%d%d%lld",&b[i].l,&b[i].r,&b[i].hd);
}
sort(b+1,b+1+n,cmp);
f[m]=0;
ll ans=0x3f3f3f3f3f3f3f3f;
for(int i=1;i<=n;i++){
for(int j=b[i].l-1;j<b[i].r;j++){
f[b[i].r]=min(f[b[i].r],f[j]+b[i].hd);
}
if(b[i].l<=e && b[i].r>=e) ans=min(ans,f[b[i].r]);
}
if(ans==0x3f3f3f3f3f3f3f3f) printf("-1\n");
else printf("%d\n",ans);
return 0;
}
线段树优化DP
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
const int maxe=9e4+1;
const int maxn=1e4+1;
const ll inf=0x3f3f3f3f3f3f3f3f;
struct Node
{
int x,y,val;
}a[maxn];
ll mn[maxe<<2];
void dfs(int x,int l,int r,int pos,ll val)
{
if(l==r)
{
mn[x]=min(mn[x],val);
return;
}
int mid=l+r>>1;
if(pos<=mid) dfs(x<<1,l,mid,pos,val);
else dfs(x<<1|1,mid+1,r,pos,val);
mn[x]=min(mn[x<<1],mn[x<<1|1]);
}
ll query(int x,int l,int r,int left,int right)
{
if(l>=left&&r<=right) return mn[x];
int mid=l+r>>1;
ll ans=inf;
if(left<=mid) ans=min(ans,query(x<<1,l,mid,left,right));
if(right>mid) ans=min(ans,query(x<<1|1,mid+1,r,left,right));
return ans;
}
int cmp(const Node &x,const Node &y)
{
return x.y<y.y;
}
int main()
{
int n,m,e;
scanf("%d%d%d",&n,&m,&e);
m-=2;e-=m;
memset(mn,0x3f,sizeof(mn));
for(int i=0;i<n;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].val),a[i].x-=m,a[i].y-=m;
dfs(1,1,e,1,0);
sort(a,a+n,cmp);
for(int i=0;i<n;i++)
{
ll now=query(1,1,e,a[i].x-1,a[i].y-1);
if(now!=inf) dfs(1,1,e,a[i].y,now+(ll)a[i].val);
}
ll ans=query(1,1,e,e,e);
printf("%lld",ans==inf?-1:ans);
return 0;
}