The 2020 ICPC Asia Shenyang Regional Programming Contest F,D,I题

题目链接

F题:

        因为我们是按照数组顺序来划分区间的,也就是说划分出来的区间只会存在该区间的数,不会有其余区间的数。假如我们处理到i位置了,前面都已经是处理完合法的区间,现在第i+1位的数字比第i个数(因为前面都处理完了,那么第i个位置就是前i个位置的最大值),那么第i+1就要合并到第i个数所在的区间,但后面区间的最小值不一定就是在第i+1个位置,也可能在第j个位置,那么我们当前这个区间就得拓展到j位置,必须保证后面区间的最小值不比当前区间的最大值小才行。

        代码1:

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
const int N=1e6+10;
const int M=5e5+10;
const int inf=0x3f3f3f3f;
const int MOD=1e9+7;

int n,m;
int a[N],mii[N];
void solve(){
    cin >> n;
    for(int i=1;i<=n;i++){
        cin >> a[i];
    }
    mii[n+1]=1e9+5;
    for(int i=n;i>0;i--){
        mii[i]=min(mii[i+1],a[i]);
    }
    int ans=0,ma=-1;
    for(int i=1;i<=n;i++){
        ma=max(ma,a[i]);
        if(ma<=mii[i+1]){
            ans++;
            ma=-1;
        }
    }
    cout << ans << endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int _=1;
    //cin >> _;
    while(_--){
        solve();
    }
}

        还有大佬是用前缀和处理的。因为数组最终是排完序的,所以我们可以利用最终数组来处理。我们是从小到大,而划分区间也同样不会不会引进别的区间的元素,也就是说如果原数组的前缀和与排序后的数组前缀和一样大小,那么当前区间就是就是需要排序的最小区间了,因为这个区间的最大值就是小于等于后面的最小值的,因为sort后的b数组是从小到大,也就是说从1到i就是这n个元素里最小的元素了,原数组只有也都是原数组里最小的i个元素才能和b数组的前缀和相等。假如有一个元素不相等,那么就相当于从i个最小数后去拿了一个稍大的数,和一定是比b数组的前缀和大的。

        代码2:

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
template <class T=int> T rd()
{
    T res=0;T fg=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}
    while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
    return res*fg;
}
const int N=1000010;
int n;
int a[N],b[N];
int main()
{
    n=rd();
    for(int i=1;i<=n;i++) a[i]=rd(),b[i]=a[i];
    sort(b+1,b+1+n);
    ll sa=0,sb=0;
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        sa+=a[i];
        sb+=b[i];
        if(sa==sb) ans++;
    }
    printf("%d\n",ans);
    
    
    return 0;
}
D题:

        相当于0,1序列,讨论区间1个数奇数个。对于区间个数问题,我们考虑前缀和sum。只有sumr和suml奇偶性相异才能让区间1个数为奇数。问题转化成区间sum奇偶对有多少的问题。我们设他们为x和y,x+y=n+1(因为前缀和最前面有个0),x*y就是奇偶对个数。由基本不等式可得x*y<=(a+b)*(a+b)/4,等式当且仅当x==y时成立,所以奇偶个数应该相近。个数就是(n+1)/2*((n+2)/2)。因为只要找100个,直接dfs,加上x和y都不能大于一半以上的剪枝即可。

        代码:

#include<iostream>
using namespace std;
const int N = 1e+5;
//int p[N]; //p[i]表示长度为i的字符串前缀中r的个数 
long long n;
int cnt = 0; //存输出的字符串个数 
string s; //存答案字符串 
void dfs(int idex, int odd, int even, bool fg) //idex表示当前位置,odd表示奇数个数,even表示偶数个数,fg表示p[idex-1]是奇数还是偶数 
{
	if(odd>(n+2)/2 || even>(n+2)/2) return ; //奇数个数和偶数个数不满足得出答案的要求,退出  
	if(idex==n)
	{
		cout << s << endl; //输出答案字符串 
		if(++ cnt>=100) exit(0); //超过100了,直接退出 
		return ;
	}
	s += 'b';
	dfs(idex+1, odd+fg, even+(fg^1), fg); //当前位置放b的情况 
	s.pop_back();
	
	s += 'r';
	dfs(idex+1, odd+(fg^1), even+fg, fg^1); //当前位置放r的情况 
	s.pop_back();
	
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	cin >> n;
	cout << (n+1)/2*((n+2)/2) << endl;
	dfs(0, 0, 1, 0);
 
	return 0;
}
I题:

        追击问题,求速度差,然后自定义参考系,令时针相对参考系静止,令分针运动。然后可以得到t *(H-1) mod HM ≤ |A|。

有两个定理:

定理1:

也就是“若a,b,c为任意3个整数,m为正整数,且(m,c)=1,则当ac≡bc(mod m)时,有a≡b(mod m)”

定理2:

若a与n互质,那么ax\equiv b(mod\ n)x\in [0, n-1]内有且仅有唯一的解.

定理2证明:设存在a*t1=b ,a*t2=b,由于定理1,a与n互质,即t1=b,t2=b,又t1,t2属于【0,n-1】,所以t1=t2。

        也就是说当a与n互质的时候,并且x取值不大于n的时候,我们就可以根据一个余数确定唯一一个解。

        t *(H-1) mod HM ≤ |A|,因为(H-1)与HM不一定互质,所以对于一个确定的余数并不能唯一确定一个解,所以我们利用定理1,令d=gcd(H-1,HM),那么式子转化成t*(H-1)/d mod HM/d <=|A|/d ,这时候(H-1)/d就与HM/d互质了。我们令b>=0&&b<=|A|/d,那么求余数为b时的解:t*(H-1) mod HM/d =b ->t mod HM/d =b,且t>=0&&t<n,可知这时候t的解是唯一的,那么我们令b取便|A|/d的整数点,那么t的解就有2*|A|/d+1(还有个0点,并且|A|是绝对值,要乘2)。因为我们是缩小了范围的(除以d),那么我们再乘回去就是答案了,也就是d*(|A|/d+1),要和M*H取min。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <deque>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <sstream>
#include <cmath>
#include <cctype>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<double, double> PUU;
#define RUSH cin.tie(), cout.tie(), ios::sync_with_stdio(false)
#define pb push_back
#define eb emplace_back
#define pai acos(-1.0)
inline ll qmi(ll a, ll b, ll mod)
{
	ll ans = 1 % mod;
	while (b)
	{
		if (b & 1)
			ans = ans * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return ans % mod;
}
inline ll inv(ll a, ll mod)
{
	return qmi(a, mod - 2, mod);
}
int main()
{
	ll H, M, A;
	cin >> H >> M >> A;
	ll pr = __gcd(H - 1, H * M);
	cout << min(H * M, pr * (2 * (A / pr) + 1));
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值