CF1552

CF1552

A:

不多说了。。。

#include<bits/stdc++.h>
using namespace std;
int t;
int a,b;
int main()
{
    cin>>t;
    while(t--){
        cin>>a>>b;
        cout<<a*b<<endl;
    }
    return 0;
}

B:

这道题其实跟有一次的B题也比较像,算是一道模拟,只需要把所有情况想好并且设计一下状态还是比较好做的。

#include<bits/stdc++.h>
using namespace std;
int T;
int a[100005],n,b[100005],m,c;
queue<int> q;
void work(){
    int maxx=0;
    cin>>n;
    int k=-1,c=-1;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
       maxx=max(a[i],maxx);
    }
    for(int i=1;i<n;i++){
        if(a[i+1]<a[i]){
            if(a[i]-a[i+1]!=k&&k!=-1){
                cout<<-1<<endl;return;
            }
            k=a[i]-a[i+1];
        }
        else{
            if(a[i+1]-a[i]!=c&&c!=-1){
                cout<<-1<<endl;return;
            }
            c=a[i+1]-a[i];
        }
    }
    if(k==-1||c==-1){
        cout<<0<<endl;return;
    }
    if(c+k<=maxx){
        cout<<-1<<endl;return;
    }
    cout<<c+k<<" "<<c<<endl;
}
int main()
{
    //ios::sync_with_stdio(false);
    cin>>T;
    while(T--){
        work();
    }
    system("pause");
    return 0;
}

C:

这次C题感觉比前几次简单点。我们可以这么想:

1.假如说当天只有一个人,那么就只能是这个人出现,因此先处理有一个人的情况。

2.贪心的考虑这道题,如果一个人出现了 \(\lceil\dfrac{m}{2}\rceil\) 次,那么剩下的人肯定出现不了\(\lceil\dfrac{m}{2}\rceil\)次。因此顺序判断是否出现次数多了即可。

#include <bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
using namespace std;
const int M=2e3+5;
const int N=1e5+5;
int n,m;
int b1[N],t1,cnt;
vector < int > a[N];
map < int , int > mp1;
int k[N];
int c[N];
int sum=-1;
void solve()
{
	mp1.clear();
	for(int i=1;i<=m;i++)  a[i].clear();
	cin>>n>>m;
	cnt=m/2;
	if(m&1)  cnt++;
	for(int i=1;i<=m;i++){
		scanf("%d",&k[i]);
		for(int j=1;j<=k[i];j++){
			int x;
			scanf("%d",&x);
			a[i].push_back(x);
		}
	}
	for(int i=1;i<=m;i++) 
        if(k[i]==1){
            mp1[a[i][0]]++;
            b1[i]=a[i][0];
        }
	for(int i=m;i;i--)
	{
		if(k[i]==1)  continue;
		int sum=-1;
		if(mp1[a[i][0]]+1<=cnt)
		{
			sum=a[i][0];
			b1[i]=sum;
			mp1[sum]++;
			continue;
		}
		for(int j=0;j<k[i];j++)
		{
			if(sum==-1||mp1[sum]>mp1[a[i][j]])
			{
				sum=a[i][j];
			}
		}
		b1[i]=sum;
		mp1[sum]++;
	}
	int flag=0;
	for(int i=1;i<=m;i++)  if(mp1[b1[i]]>cnt)  flag=1;
	if(flag)  puts("NO");
	else
	{
		puts("YES");
		for(int i=1;i<=m;i++)  printf("%d ",b1[i]);
		puts("");
	}
}
signed main()
{
//	ios::sync_with_stdio(false);
	int T=1;
	cin>>T;
	while(T--)  solve(); 
	return 0;
}

D:

这次D一开始没有想好怎么处理,后来看了题解之后发现自己问题太大了。。。

考虑一下两种情况:

1.当前 \(a[i],a[i+1]\) 的最大公约数是1,而且 \(a[i]和a[i+2]\) 最大公约数不是1,那么我们就直接将 \(a[i+1]\) 出队即可。

2.\(a[i]和a[i+2]\) 的最大公约数是1,但是不能立即排出,那么加入队列中即可。

我们可以用链表来优化处理前后问题,\(next[n]=1\) 即可。

在队列中存储可以用 \(pair<int,int>\) 用来处理前后。

还有一些细节在代码中:

#include<bits/stdc++.h>
using namespace std;
int T;
const int N=1e5+5;
#define pii pair<int,int>
#define mk make_pair 
int n,nxt[N],a[N],v[N],b[N];
void work(){
    int cnt=0;
    memset(v,0,sizeof(v));
    queue<pii> q; while(q.size()) q.pop();
    cin>>n;
    for(int i=0;i<=n;i++) 
        nxt[i]=i+1; nxt[n]=1;
    for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
    for(int i=1;i<n;i++) 
        if(__gcd(a[i],a[i+1])==1) 
            q.push(mk(i,i+1));
    if(__gcd(a[1],a[n])==1) 
        q.push(mk(n,1));
    while(q.size()){
        pii x=q.front();q.pop();
        if(v[x.first]||v[x.second]) continue;//是否访问过,不重复
        b[++cnt]=x.second;
        v[x.second]=1;//后面的访问了
        if(x.first==x.second) break;
        nxt[x.first]=nxt[x.second];//用链表处理前后
        if(__gcd(a[x.first],a[nxt[x.first]])==1)
            q.push(mk(x.first,nxt[x.first]));
    }
    cout<<cnt;
    for(int i=1;i<=cnt;i++) printf(" %d",b[i]);
    cout<<endl;
    return;
}
int main()
{
    cin>>T;
    while(T--){
        work();
    }
    //system("pause");
    return 0;
}

F:

首先离散化。然后记\(f_i\) 为被在 \(i\) 点的传送门传走再走回到 \(i\) 点的时间。
若该位置没有传送门,则记 \(f_i=0\)
容易发现已经过的传送门肯定是开启的,因此有 \(f_i=x_i-y_i+\sum f_j,x_j\in[y_i,x_i-1]\)
即路程长度加上被之间所有的传送门传一遍所需时间,发现这显然可以用前缀和维护。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=4e5+5;
const int mod=998244353;
struct node{
    int x,y,s;
}a[N];
int b[N],sum[N],f[N],ans,n;
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld%lld%lld",&b[i*2-1],&b[i*2],&a[i].s);
        a[i].x=b[i*2-1];a[i].y=b[i*2];
    }
    sort(b+1,b+1+2*n);
    for(int i=1;i<=n;i++){
        a[i].x=lower_bound(b+1,b+1+2*n,a[i].x)-b;
        a[i].y=lower_bound(b+1,b+1+2*n,a[i].y)-b;
    }//离散化
    int now=1;
    for(int i=1;i<=2*n;i++){
        while(i==a[now].x&&now<=n){
            f[i]=(b[a[now].x]-b[a[now].y]+mod)%mod;
            f[i]=(f[i]+sum[a[now].x-1]-sum[a[now].y-1]+mod)%mod;
            if(a[now].s==1) ans=(ans+f[i])%mod;
            now++;
        }//求 fi 并统计答案
        sum[i]=(sum[i-1]+f[i])%mod;//前缀和维护
    }
    ans=(ans+b[a[n].x]+1)%mod;//加上路径总长度
    printf("%lld\n",ans);
    return 0;
}

posted @ 2021-08-19 19:51  Evitagen  阅读(49)  评论(0编辑  收藏  举报