这场比赛爆零了,感觉自己还是弱。。而且有点过于care rating了。做比赛还开小号,不敢用大号。根本没有攻克难题的魄力和勇气。
以后只打一个号就好了,实力增强了总是能涨的。这场的题应该还是偏简单的,比赛的时候还是各种2各种想不出,感谢round305暴露了我很多弱点。
每过一秒,h1=(x1*h1+y1)%m,h2=(x2*h2+y2)%m。求使h1=a1,h2=a2同时满足的最早时刻。
找到使h1第一次等于a1的时间,再找使它循环的时间,对h2同理。然后弄到set里面乱搞就好了。更科学的做法应该是扩展欧几里德。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 1e9;
int main(){
ll m,h1,a1,x1,y1;
ll h2,a2,x2,y2;
cin>>m;
cin>>h1>>a1;
cin>>x1>>y1;
cin>>h2>>a2;
cin>>x2>>y2;
//
ll ans1=1;
for(;ans1<=m+1;ans1++){
h1=x1*h1+y1;
h1%=m;
if(h1==a1){
break;
}
}
ll ans2=1;
for(;ans2<=m+1;ans2++){
h2=x2*h2+y2;
h2%=m;
if(h2==a2){
break;
}
}
ll cyc1=1;
for(;cyc1<=m+1;cyc1++){
h1=x1*h1+y1;
h1%=m;
if(h1==a1){
break;
}
}
ll cyc2=1;
for(;cyc2<=m+1;cyc2++){
h2=x2*h2+y2;
h2%=m;
if(h2==a2){
break;
}
}
bool ok=1;
if(ans1>m+1||ans2>m+1)ok=0;
if(ok){
if(cyc1>m+1)cyc1=0;
if(cyc2>m+1)cyc2=0;
set<ll> s;
for(int i=0;i<=m;i++){
s.insert(ans1+cyc1*i);
}
for(int i=0;i<=m;i++){
if(s.count(ans2+cyc2*i)){
cout<<ans2+cyc2*i<<endl;
return 0;
}
}
cout<<-1;
}else{
cout<<-1;
}
return 0;
}
长度为n的数列,求连续长度x=1~n的一串数中,最小值的最大值。
维护一个单调栈,使值递增。出栈时维护长度并尝试更新答案,具体见代码。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 1e9;
struct node{
int val;
int len;
node(int val,int len):val(val),len(len){
}
node(){
}
};
stack<node> sta;
int a[200010];
int ans[200010];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
int curlen=0;
while(sta.size() && sta.top().val>=a[i]){
int val=sta.top().val;
curlen+=sta.top().len;
sta.pop();
ans[curlen]=max(ans[curlen],val);
}
sta.push(node(a[i],curlen+1));
}
int curlen=0;
while(sta.size()){
int val=sta.top().val;
curlen+=sta.top().len;
sta.pop();
ans[curlen]=max(ans[curlen],val);
}
for(int i=n;i>=1;i--){
if(ans[i]<ans[i+1])ans[i]=ans[i+1];
}
for(int i=1;i<=n;i++){
printf("%d ",ans[i]);
}cout<<endl;
return 0;
}
另外我还看到了一个使用并查集的做法。先排序,从大到小标记元素,并查集维护当前元素与左右已被标记的元素连起来的最大长度。
有n个数,初始均为禁用状态。有q个询问,每次改变一个数的状态(禁用<-->启用)。问启用的那些数里面,有多少对数满足最大公约数为1。
这是我第一道用容斥原理做的题。。本来没想法,看了题解后发现非常精妙。首先把1~500000的所有素因子筛出来(注意到每个数最多有6个不同的素因子)。假设新增或删除的数与其他启用的数最大公约数都等于1,那么新增或删除后,答案的改变量就是除了它之外,启用的数的个数(新增加上,删除减去)。但是,新增或删除的那个数,可能与某些数的最大公约数不为1,这就需要用容斥原理来处理。比如ai共有6个素因子,那么就用6位二进制数把它的素因子的所有子集表示出来,为所有素因子集合计数,维护答案。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 1e9;
const int maxn =200010;
const int maxa =500000;
int a[maxn];
bool state[maxn];
vector<int> factors[maxa+1];
int cnt[maxa+1]; //统计素因子的集合
void init(){
for(int i=2;i<=500000;i++){
if(!factors[i].size()){
for(int j=i;j<=500000;j+=i){
factors[j].push_back(i);
}
}
}
}
static ll ans=0;
static int tot=0;
void fun(int num,int flag){
int t=1<<factors[num].size();
ans+=tot*flag;
//枚举子集
for(int i=1;i<t;i++){
int tmp=1; //num素因子的子集中,所有元素的积。
int bit=0; //num素因子的子集中,有多少个元素。
for(int j=0;j<factors[num].size();j++){
if(i&(1<<j)){
tmp*=factors[num][j];
bit++;
}
}
if(flag==-1)cnt[tmp]+=flag;
int one;
if(bit&1)one=1;
else one=-1;
if(cnt[tmp]){
//容斥维护答案,加多了减去,减多了加上。。。
ans-=cnt[tmp]*flag*one;
}
if(flag==1)cnt[tmp]+=flag;
}
}
int main(){
init();
int n,q;
cin>>n>>q;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int x;
for(int i=1;i<=q;i++){
scanf("%d",&x);
if(state[x]){
tot--;
state[x]=0;
fun(a[x],-1);
}else{
state[x]=1;
fun(a[x],1);
tot++;
}
printf("%I64d\n",ans);
}
return 0;
}