zoukankan      html  css  js  c++  java
  • ICPC Mid-Central USA Region 2019 题解

    队友牛逼!带我超神!蒟蒻的我还是一点一点的整理题吧...

    Dragon Ball I

    这个题算是比较裸的题目吧....学过图论的大概都知道应该怎么做。题目要求找到七个龙珠的最小距离。很明显就是7个龙珠先后去的排列,然后用dijkstra预处理出来每个龙珠到所有其他的点的最短距离啊。最后dfs暴力枚举排列统计答案就行。这里有一些小的细节问题题目中最大的距离为2e9,所以0x3f可能有点不够,还真是细节决定成败啊,不亏我Wrong了一发!

    //不等,不问,不犹豫,不回头.
    #include<bits/stdc++.h>
    #define _ 0
    #define ls p<<1
    #define db double
    #define rs p<<1|1
    #define P 1000000007
    #define ll long long
    #define INF 1000000000
    #define get(x) x=read()
    #define PLI pair<ll,int>
    #define PII pair<int,int>
    #define ull unsigned long long
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(x,y,z) for(int x=y;x<=z;++x)
    #define fep(x,y,z) for(int x=y;x>=z;--x)
    #define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
    using namespace std;
    const int N=200010;
    int n,m,link[N],id[10],tot,vis[N],d[10][N];
    struct bian{ll y,v,next;}a[N<<1]; 
    ll ans=1e18;
    priority_queue<pair<ll,int> >q;
    
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    
    inline void add(int x,int y,int v)
    {
    	a[++tot].y=y;a[tot].v=v;a[tot].next=link[x];link[x]=tot; 
    }
    
    inline void dijkstra(int s)
    {
    	rep(i,1,n) d[s][i]=2e9;
    	memset(vis,0,sizeof(vis));
    	d[s][id[s]]=0;
    	q.push({0,id[s]});
    	while(q.size())
    	{
    		int x=q.top().second;q.pop();
    		if(vis[x]) continue;
    		vis[x]=1;
    		for(int i=link[x];i;i=a[i].next)
    		{
    			int y=a[i].y;
    			if(d[s][y]>d[s][x]+a[i].v)
    			{
    				d[s][y]=d[s][x]+a[i].v;
    				q.push({-d[s][y],y});
    			}
    		}
    	}
    }
    
    inline void dfs(int now,int cnt,ll s)
    {
    	if(cnt==7) 
    	{
    		ans=min(ans,s);
    		return;
    	}
    	rep(i,1,7) 
    	{
    		if(!vis[i])
    		{
    			vis[i]=1;
    			dfs(i,cnt+1,s+d[now][id[i]]);
    			vis[i]=0;
    		}
    	}
    }
    
    int main()
    {
        //freopen("1.in","r",stdin);
    	get(n);get(m);
    	rep(i,1,m)
    	{
    		int get(x),get(y),get(v);
    		add(x,y,v);add(y,x,v);
    	}
    	id[0]=1;
    	rep(i,1,7) get(id[i]);
    	rep(i,0,7) dijkstra(i);
    	rep(i,1,7)
    	{
    		if(d[0][id[i]]==2e9) 
    		{
    			puts("-1");
    			return 0;
    		}
    	}
    	memset(vis,0,sizeof(vis));
    	dfs(0,0,0);
    	putl(ans);
        return (0^_^0);
    }
    //以吾之血,铸吾最后的亡魂.
    

    Farming Mars

    这个算是比较裸的数据结构的题了...简化下题意就是:给你一个序列,有询问,问一个区间中有没有一个数的个数大于等于区间的一半(向上取整).先不想那么多,看到10000的范围,我这暴脾气,先打个暴力试试,(O(n^2))闯天下啊,真过了,赛后就不能这样敷衍了事了。仔细想想不就是权值计数吗?区间查询最大值,写个主席树不就行了?...太水了题...不对不对,这不太行啊,主席树没法维护区间最大值啊...假了假了假了...原来小丑竟是我自己...等等等..等等,这个题问的不是区间众数的次数吗?分块啊!还是分块大法好!莫队!所有(O(nsqrt n))的数据结构都行。
    先放个暴力的代码:

    //不等,不问,不犹豫,不回头.
    #include<bits/stdc++.h>
    #define _ 0
    #define ls p<<1
    #define db double
    #define rs p<<1|1
    #define P 1000000007
    #define ll long long
    #define INF 1000000000
    #define get(x) x=read()
    #define PLI pair<ll,int>
    #define PII pair<int,int>
    #define ull unsigned long long
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(x,y,z) for(int x=y;x<=z;++x)
    #define fep(x,y,z) for(int x=y;x>=z;--x)
    #define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
    using namespace std;
    const int N=10010;
    int n,m,a[N],ct[N],num;
    db b[N],t[N];
     
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
     
    inline int find(db s) {return lower_bound(b+1,b+num+1,s)-b;}
     
    inline void init()
    {
        get(n);get(m);
        rep(i,1,n) cin>>t[i],b[i]=t[i];
        sort(b+1,b+n+1);
        num=unique(b+1,b+n+1)-b-1;
        rep(i,1,n) a[i]=find(t[i]);
    }
     
    int main()
    {
        //freopen("1.in","r",stdin);
        init();
        rep(i,1,m)
        {
            int get(l),get(r);
            rep(j,l,r) ct[a[j]]++;
            bool flag=false;
            rep(j,l,r) if(ct[a[j]]>=((r-l+1)/2)+1)
            {
                flag=true;
                break;
            }
            if(flag) puts("usable");
            else puts("unusable");
            rep(j,l,r) ct[a[j]]=0;
        }
        return (0^_^0);
    }
    //以吾之血,铸吾最后的亡魂.
    

    回滚莫队的代码,分块由于前不久练过,就不再写一遍了,真的很费脑细胞...

    //不等,不问,不犹豫,不回头.
    #include<bits/stdc++.h>
    #define _ 0
    #define ls p<<1
    #define db double
    #define rs p<<1|1
    #define P 1000000007
    #define ll long long
    #define INF 1000000000
    #define get(x) x=read()
    #define PLI pair<ll,int>
    #define PII pair<int,int>
    #define ull unsigned long long
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(x,y,z) for(int x=y;x<=z;++x)
    #define fep(x,y,z) for(int x=y;x>=z;--x)
    #define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
    using namespace std;
    const int N=10010;
    int a[N],num,n,m,ans[N];
    int belong[N],bl[N],br[N],block,bnum,cnt1[N],cnt2[N];
    db t[N],b[N]; 
    struct wy{int l,r,id;}q[N];
    
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    
    inline int find(db s) {return lower_bound(b+1,b+num+1,s)-b;}
    
    inline void build()
    {
    	block=sqrt(n);bnum=n/block;
    	if(n%block) bnum++;
    	rep(i,1,n) belong[i]=(i-1)/block+1;
    	rep(i,1,bnum) bl[i]=(i-1)*block+1,br[i]=i*block;
    	br[bnum]=n;
    }
    
    inline bool cmp(wy a,wy b)
    {
    	return (belong[a.l]!=belong[b.l]?belong[a.l]<belong[b.l]:a.r<b.r);
    }
    
    inline void init()
    {
        get(n);get(m);
        rep(i,1,n) cin>>t[i],b[i]=t[i];
        sort(b+1,b+n+1);
        num=unique(b+1,b+n+1)-b-1;
        rep(i,1,n) a[i]=find(t[i]);
        rep(i,1,m) get(q[i].l),get(q[i].r),q[i].id=i;
        build();
        sort(q+1,q+m+1,cmp);
    }
    
    inline void solve()
    {
    	int i=1;
    	rep(j,1,bnum)
    	{
    		int now=0;
    		int l=br[j]+1,r=br[j];
    		memset(cnt1,0,sizeof(cnt1));
    		for(;i<=m&&belong[q[i].l]==j;++i)
    		{
    			int temp;
    			int ql=q[i].l,qr=q[i].r;
    			if(belong[ql]==belong[qr])
    			{
    				temp=0;
    				rep(k,ql,qr) cnt2[a[k]]=0;
    				rep(k,ql,qr) cnt2[a[k]]++,temp=max(temp,cnt2[a[k]]);
    				ans[q[i].id]=(temp>=(qr-ql+1)/2+1?1:0);continue;
    			}
    			while(r<qr) cnt1[a[++r]]++,now=max(now,cnt1[a[r]]);
    			temp=now;
    			while(l>ql) cnt1[a[--l]]++,now=max(now,cnt1[a[l]]);
    			ans[q[i].id]=(now>=(qr-ql+1)/2+1?1:0);
    			now=temp;
    			while(l<br[j]+1) cnt1[a[l++]]--; 
    		}
    	}
    	rep(i,1,m)
    	{
    		if(ans[i]) puts("usable");
    		else puts("unusable");
    	}
    } 
    
    int main()
    {
       // freopen("1.in","r",stdin);
    	init();
    	solve();
        return (0^_^0);
    }
    //以吾之血,铸吾最后的亡魂.
    
    

    Sum and Product

    队友牛逼带我超神....
    首次看这个题,题意很好理解就是找到有多少个子区间,使得这个区间里所有元素的乘积等于和。...
    看起来好复杂...但仔细思考一下,全部元素的乘积,...,这玩意是不是有点大....连续64个2想乘就爆longlong了,那全部元素的和的大小范围呢?(n)(2e5),(a_i)(1e9),也就是说这里的元素和最大值为(2e14),那乘积超过这个不就一定不合法了吗?那直接暴力,然后break。T了....为啥会T啊...昂,对了序列中可能有很多的1使得乘积长时间不变,那我们考虑能不能直接跳过这些乘积,直接和有效的数组想乘,我这里记了一个id[i]数组表示i之后一个非1的位置,然后固定左端点,寻找去合法右端点的数目,由于中间全部是1,累乘的结果很好维护,累加的话根据下标计算也很容易。考虑这之间有没有可能会出现合法的右端点,由于全部是1,所以乘积不变,和一直加,若之前和<乘积。并且这里1的个数又足够多的话,我们就能在一堆1中实现和=积的情况,并且最多一次,因为相等之后,和还往上加,积就不变,一定不和法,那这样就好办了,我们在跳的一堆1中看有没有符合条件的,跳过后看有没有符合条件。这样最多跳64次。总复杂度为(O(nlogn))
    注意这里用除法代替乘法,避免爆long long.

    //不等,不问,不犹豫,不回头.
    #include<bits/stdc++.h>
    #define _ 0
    #define ls p<<1
    #define db double
    #define rs p<<1|1
    #define P 1000000007
    #define ll long long
    #define INF 1000000000
    #define get(x) x=read()
    #define PLI pair<ll,int>
    #define PII pair<int,int>
    #define ull unsigned long long
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(x,y,z) for(int x=y;x<=z;++x)
    #define fep(x,y,z) for(int x=y;x>=z;--x)
    #define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
    using namespace std;
    const int N=2e5+10;
    const ll MAX=2e14;
    int n,a[N],id[N],now;
    
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    
    int main()
    {
        //freopen("1.in","r",stdin);
    	get(n);
    	rep(i,1,n) get(a[i]);
    	int now=n;
    	fep(i,n,1) 
    	{
    		id[i]=now;
    		if(a[i]!=1) now=i;
    	}
    	id[n]=0;
    	int ans=0;
    	rep(i,1,n) //统计每个左端点合法的右端点 
    	{
    		ll mt=a[i],sm=a[i];
    		now=i;
    		while(id[now])
    		{
    			if(MAX/mt<a[id[now]]) break;
    			if(sm<mt&&sm+(id[now]-now-1)>=mt) ++ans;
    			mt=mt*a[id[now]];
    			sm=sm+a[id[now]]+(id[now]-now-1);
    			if(mt==sm) ++ans;
    			now=id[now];
    		}
    	}
    	put(ans);
        return (0^_^0);
    }
    //以吾之血,铸吾最后的亡魂.
    
    

    J True/False Worksheet

    这个题主要是思路被限制住了,想到并查集后就完全想着用数学方法解决问题了...
    其实看到(n)(5000)的时候就可以考虑(dp)的写法了。
    首先考虑无解的情况,就是一个要求不相同的区间里面的数被迫相同,我们直接预处理就行。
    考虑(DP)怎样设状态,由于题目中的限制条件是一个区间必须是相同或不能全部相同,所以我们状态中就应该能体现这个相同与否的状态。考虑设(f[i][j])表示从第(j)位到第(i)位都相同,且到(i)位结尾的方案数。转移时可以想不用考虑限制条件。当第(i)个和第(i-1)个保持一样时(f[i][j]=f[i-1][j]),当第(i)个和(i-1)不一样时,(f[i][i]=)(sum_{k=1}^{i-1}{f[i-1][k]})。那么接下来考虑相同的限制条件,比如说从l到i都必须是相同的,那么(f[i][1],f[i][2]...f[i][l])都是合法的状态,考虑不相同的限制条件,比如从l到i都不相同,那么从(f[i][l+1],f[i][l+2],...,f[i][i])都是合法的,既然如此我们就可以得知每个i的所有合法状态有哪些即(diff[i]+1-same[i])这些状态是合法的。至于当(f[i][i])转移时我们可以对(i-1)的转态枚举时,可以直接从(1)(i-1),因为在(i-1)时我们只保存了合法的状态。同理在统计答案时,我们可以直接求和,不必在乎是否合法,因为我们只保存了合法的状态的值,能转移过来的一定是合法的。

    //不等,不问,不犹豫,不回头.
    #include<bits/stdc++.h>
    #define _ 0
    #define ls p<<1
    #define db double
    #define rs p<<1|1
    #define P 1000000007
    #define ll long long
    #define INF 1000000000
    #define get(x) x=read()
    #define PLI pair<ll,int>
    #define PII pair<int,int>
    #define ull unsigned long long
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(x,y,z) for(int x=y;x<=z;++x)
    #define fep(x,y,z) for(int x=y;x>=z;--x)
    #define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
    using namespace std;
    const int N=5010;
    int n,m,f[N][N];//f[i][j]表示从j到i都相同的方案数
    int same[N],diff[N]; 
    bool flag=true;
    char c[N];
    
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    
    inline void init()
    {
    	get(n);get(m);
    	rep(i,1,n) same[i]=i;
    	rep(i,1,m)
    	{
    		int get(x),get(y);
    		scanf("%s",c+1);
    		if(c[1]=='s') same[y]=min(same[y],x);
    		else diff[y]=max(diff[y],x);
    	}
    	rep(i,1,n) if(diff[i]>=same[i]) flag=false;
    	if(!flag) puts("0");
    }
    
    inline void solve()
    {
    	f[1][1]=2;
    	rep(i,2,n) 
    	{
    		rep(j,diff[i]+1,same[i]) f[i][j]=(f[i][j]+f[i-1][j])%P;
    		if(same[i]==i)
    		{
    			rep(j,1,i-1) f[i][i]=(f[i][i]+f[i-1][j])%P;
    		}
    	}
    	int ans=0;
    	rep(i,1,n) ans=(ans+f[n][i])%P;	
    	put(ans);
    }
    
    int main()
    {
        //freopen("1.in","r",stdin);
    	init();
    	if(flag) solve();
        return (0^_^0);	
    }
    //以吾之血,铸吾最后的亡魂.
    
    
  • 相关阅读:
    Neptune w800开发版ubuntu linux环境编译通过——如何搭建开发环境
    neptune HarmonyOS开发板视频教程-环境搭建-编译-烧录-外设控制
    Neptune开发板与hiSpark开发板底板的管脚不兼容
    《设计心理学》要点(上)
    NLP(三十二):大规模向量相似度检索方案
    VIM编辑器设置
    (十一)pytorch加速训练的17种方法
    (十)pytorch多线程训练,DataLoader的num_works参数设置
    NLP(三十一):用transformers库的BertForSequenceClassification实现文本分类
    NLP(三十):BertForSequenceClassification:Kaggle的bert文本分类,基于transformers的BERT分类
  • 原文地址:https://www.cnblogs.com/gcfer/p/15163811.html
Copyright © 2011-2022 走看看