N个灯,N个开关,现在按顺序按M个开端,按开关i的时候,大于等于i的并且开着的灯都会被关闭,问N个灯分别是被哪一个开关关掉的。直接模拟了..先关的先标记..
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m;
int a[220],b[220];
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
memset(a,0,sizeof a);
for (int i=1; i<=n; i++)
{
scanf("%d",&b[i]);
for (int j=b[i]; j<=n; j++)
if (a[j]==0) a[j]=b[i];
}
for (int i=1; i<=n; i++)
cout<<a[i]<<" ";
cout<<endl;
return 0;
}
P2: Mashmokh and Tokens
N天,两个参数a,b。每天一个代币数W,W个代币可以换成(W*A/B)向下取整元钱,问每天在换到最多钱的情况下能省下来多少代币。因为牵扯到向下取整,所以只要每次W*A%B数量的都是多余的,而多出来的这部分再除以B就是能省下来的代币数,所以答案就是(W*A%B)/A.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef __int64 ll;
int a,b,n,p,q;
ll aa,bb,m;
ll w[222222];
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d%d%d",&n,&a,&b);
for (int i=1; i<=n; i++)
{
aa=a;
bb=b;
scanf("%I64d",&m);
cout<<(m*aa%bb)/aa<<" ";
}
cout<<endl;
return 0;
}
p3: Mashmokh and Numbers
N个数,取K分,每次可以再N个数组成的数列里取前两个数,分数是这两个数的GCD,求构造一个可行序列。
因为要求数列里的数<=1e9,而K最大为1e8,所以必然可以让序列的前两项得到K-(N-2)/2的分数,然后后面的全部用素数补齐。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef __int64 ll;
const int N=10100000;
int prime[1200000], np;
bool vis[N];
ll a[303000],b[303000];
void get_prime()
{
np = 0;
memset(vis, 0, sizeof(vis));
for(int i = 2; i < N; ++i)
{
if (!vis[i])
{
prime[np++] = i;
for(int j = i+i; j < N; j +=i) vis[j] = 1;
}
}
}
int cnt=0;
int n,k;
ll p,q,r,c;
bool f[10100000];
const int inf=1000000000;
int main()
{
get_prime();
// cout<<np<<endl;
for (int i=0; i+1<np; i+=2)
{
a[cnt]=prime[i];
b[cnt]=prime[i+1];
cnt++;
if (cnt>=300000) break;
}
while(~scanf("%d%d",&n,&k))
{
if (n==1)
{
if (k==0) cout<<1<<endl;
else cout<<"-1"<<endl;
continue;
}
c=k-(n-2)/2;
if (c<=0)
{
cout<<"-1"<<endl;
continue;
}
cout<<c<<" "<<c*2<<" ";
memset(f,true,sizeof f);
if (2*c<N) f[c]=f[c*2]=false;
int cnt=1;
int i;
for (i=3; i<=n; i++)
{
while(!f[a[cnt]]) cnt++;
cout<<a[cnt]<<" ";
cnt++;
}
cout<<endl;
}
return 0;
}
p4: Mashmokh and ACM
N个数,其中最大数是K,序列A是好序列当且仅当Ai|Ai+1,问这样的好数列有多少个。
DP[i][j]记录当前位置为i,长度为j的数列有多少种。转移方程dp[i][j]+=sum(dp[k][j-1], i|k ),枚举k的倍数类似一个线性的筛法,所以总复杂度略大于2000*2000.
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef __int64 ll;
int n,m,k;
ll dp[2222][2222];
ll sum[2222];
const int mod=1000000007;
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(dp,0,sizeof dp);
memset(sum,0,sizeof sum);
for (int i=1; i<=n; i++)
dp[i][1]=1;
for (int j=2; j<=m; j++)
for (int i=1; i<=n; i++)
for (int k=i; k<=n; k+=i)
{
dp[i][j]+=dp[k][j-1];
dp[i][j]%=mod;
}
ll ans=0;
for (int i=1; i<=n; i++)
{
ans+=dp[i][m];
if (ans>mod) ans-=mod;
}
cout<<ans<<endl;
}
return 0;
}
P5: Mashmokh and Reverse Operation 归并+BIT
2^N个数,每次查询一个p,将数列按2^p分组,每组翻转,并且输出翻转后整个序列的逆序对数。
首先用类似归并排序的方法预处理下,第0层是整个序列,第一层是一半,一半,依次向下。
用inv[i]记录一下当前深度为i时逆序对的数量,sum[i]记录深度为i时左半长度*右半长度,两边有多少种比配情况,eq[i]记录一下左半和右半相等的匹配情况,那么在深度为i的区间翻转的时候,新的inv[i]=sum[i]-eq[i]-inv[i],这样就可以实现单层O(1)查询了。查询的时候,从低向高枚举层数,一边更新inv一边统计答案,总复杂度1e6*log(1e6).
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn=1300000;
int n,m,p,q;
int a[maxn];
int b[maxn];
ll inv[maxn];
ll sum[maxn];
ll eq[maxn];
struct BIT
{
ll dt[maxn];
void init()
{
memset(dt,0,sizeof dt);
}
int lowbit(int x)
{
return x&-x;
}
void modify(int x,ll c=1)
{
for (int i=x; i<maxn; i+=lowbit(i))
{
dt[i]+=c;
}
}
ll query(int x)
{
ll res=0;
for (int i=x; i>0; i-=lowbit(i))
{
res+=dt[i];
}
return res;
}
}bit;
void slove(int l,int r,int d)
{
if (l==r) return;
int m=(l+r)>>1;
slove(l,m,d+1);
slove(m+1,r,d+1);
ll len=(ll)(m-l+1)*(ll)(r-m);
sum[d]+=len;
for (int i=m+1; i<=r; i++) bit.modify(a[i]);
for (int i=l; i<=m; i++)
{
inv[d]+=bit.query(a[i]-1);
eq[d]+=bit.query(a[i])-bit.query(a[i]-1);
}
for (int i=m+1; i<=r; i++) bit.modify(a[i],-1);
}
int main()
{
// freopen("in.txt","r",stdin);
while(~scanf("%d",&n))
{
int nn=n;
n=1<<n;
for (int i=1; i<=n; i++) scanf("%d",&a[i]);
memcpy(b,a,sizeof a);
sort(b+1,b+n+1);
int size=unique(b+1,b+1+n)-(b+1);
for (int i=1; i<=n; i++)
a[i]=lower_bound(b+1,b+1+size,a[i])-(b+1)+1;
bit.init();
memset(sum,0,sizeof sum);
memset(inv,0,sizeof inv);
memset(eq,0,sizeof eq);
slove(1,n,0);
scanf("%d",&m);
ll ans=0;
for (int i=0; i<nn; i++)
ans+=inv[i];
while(m--)
{
int k;
scanf("%d",&k);
k=nn-k;
for (int i=k; i<=nn; i++)
{
ans-=inv[i];
inv[i]=sum[i]-eq[i]-inv[i];
ans+=inv[i];
}
cout<<ans<<endl;
}
}
return 0;
}