codeforces round705 解题报告
A
贪心,一眼题
#include<bits/stdc++.h>
#define MAXN 2100
using namespace std;
int n, k, T,num,a[MAXN];
int main()
{
cin >> T;
while(T--)
{
cin >> n >> k;
num = max(0, n - k);
if(k&1)
{
num += (k - 1) / 2;
// if(num)
{
cout << num << endl;
for (int i = k+1; i <= n;i++)
cout << i<<" ";
for (int i = 1; i <= (k - 1) / 2;i++)
cout << k - i << " ";
cout << endl;
}
}
else
{
num += (k ) / 2;
// if(num)
{
cout << num << endl;
for (int i = k+1; i <= n;i++)
cout << i<<" ";
for (int i = 1; i <= (k) / 2;i++)
cout << k - i << " ";
cout << endl;
}
}
}
}
B
在一个外星球上的时间表示法与地球上的是类似的,一天有h个小时,一个小时有m分钟,这个地球上的居民喜欢看是时钟在镜子中的反射,我们会给定一个时刻,求最近的一个合法的时刻,如果给定的时刻是合法的,那么直接输出即可。
模拟。可能最近太久没写这这种题了,一遇到细节就经常莫名其妙wa。
#include<bits/stdc++.h>
#define MAXN 2100
using namespace std;
int rev[10]={0,1,5,-1,-1,2,-1,-1,8,-1};
string s;
int T, h, m;
int st_h, st_m;
bool check(int hh,int mm)
{
int h1 = hh / 10, h2 = hh % 10;
int m1 = mm / 10, m2 = mm % 10;
if(rev[h1]==-1||rev[h2]==-1)
return 0;
if(rev[m1]==-1||rev[m2]==-1)
return 0;
if(h2*10+h1>=m||m2*10+m1>=h)
return 0;
return 1;
}
void pri(int hh,int mm)
{
if(hh<10)
cout << "0" << hh;
else
cout << hh;
if(mm<10)
cout<<":0" << mm << endl;
else
cout<<":" << mm << endl;
}
int main()
{
cin >> T;
while(T--)
{
bool find_ans = 0;
cin >> h >> m;
cin >> s;
st_h = (s[0] - '0') * 10 + (s[1] - '0');
st_m = (s[3] - '0') * 10 + (s[4] - '0');
for (int i = st_m; i < m;i++)
if(check(st_h,i))
{
pri(st_h, i);
find_ans = 1;
break;
}
if(find_ans==0)
{
for (int i = st_h + 1; i < h;i++)
{
for (int j = 0; j < m;j++)
{
if(check(i,j))
{
pri(i, j);
find_ans = 1;
break;
}
}
if(find_ans==1)
break;
}
if(!find_ans)
pri(0, 0);
}
}
}
C
给你一个小写字母串,和k,让你找到一个字典序比原串大,同时又在新串中字典序最小且满足每个字母出现的次数能够被k整除。
又要维护最大,又要维护最小很麻烦。于是我们想办法倒序遍历,同时记录每个位置之前至少需要多少个字母才能满足条件,当 p r e + i < = n − 1 pre+i<=n-1 pre+i<=n−1时,就可以只替换该位置后面的串。而后面的操作只需满足字典序最小就好了。
#include<bits/stdc++.h>
#define MAXN 2100
#define forn(i, n) for(int i = 1; i <= n;i++)
using namespace std;
int T, n, k,pre;
int a[30],ans_find,lst_pre;
string s;
int change(int x)
{
return (k - a[x] % k) % k;
}
void pri(int x,int ch)
{
for (int i = 0; i < x; i++)
cout << s[i];
cout<<char(ch+'a'-1);
for (int i = x + 1; i < n;i++)
{
forn (j,26)
{
if(change(j)!=0)
{
cout << char(j + 'a' - 1);
a[j]++;
}
}
}
cout << endl;
}
int main()
{
cin >> T;
while(T--)
{
cin >> n >> k;
cin >> s;
memset(a, 0, sizeof(a));
pre = 0;
ans_find = 0;
for (int i = 0; i < s.length();i++)
a[s[i] - 'a' + 1]++;
if(n%k)
{
cout << "-1"<<endl;
continue;
}
forn(i, 26)
pre += change(i);
if(pre==0)
{
cout << s << endl;
continue;
}
for (int i = n - 1; i >= 0;i--)
{
if(ans_find)
break;
int ch = s[i]-'a'+1;
pre -= change(ch);
a[ch]--;
pre += change(ch);
lst_pre=pre;
for (int j = ch + 1; j <= 26;j++)
{
if(ans_find)
break;
pre -= change(j);
a[j]++;
pre += change(j);
if(pre+i<=n-1)
{
ans_find = 1;
pri(i,j);
break;
}
a[j]--;
pre=lst_pre;
}
}
}
}
D
给定一组数据,然后每次对一个位置上的数乘上另一个数,每次操作之后询问这个序列的gcd
可以遇见的是每次询问得到的答案gcd只会变大,不可能变小。我们便用一种数据结构(map)来维护每个数的每个质因子的次数,再用另一个map记录每个质因子相应次幂出现的次数,当这个次数等于n时,就可以更新gcd
#include<bits/stdc++.h>
#define MAXN 210000
#define ll long long
#define int long long
#define forn(i, n) for(int i = 1; i <= n;i++)
using namespace std;
const ll mod = 1e9 + 7;
int cnt,m, n, k,pre,ans;
int prime[MAXN],v[MAXN],a[MAXN];
map<int, map<int, int>> q, cnt_yinzi;
//q里是每个位置上每个因子的个数
//cnt_yinzi里是每个因子的每个次方在序列里出现了多少次
void get_prime()
{
int nn = MAXN;
for (int i = 2; i <= nn;i++)
{
if(!v[i])
{
prime[++cnt] = i;
v[i] = i;
}
for (int j = 1; j <= cnt;j++)
{
if(prime[j]*i>nn||prime[j]>i)
break;
v[prime[j] * i] = prime[j];
}
}
}
void divide(int num,int x)
{
for (int i = 1; i <= cnt;i++)
{
if(x==1)
break;
while(x%prime[i]==0)
{
q[num][i]++;
cnt_yinzi[i][q[num][i]]++;
x/=prime[i];
if(cnt_yinzi[i][q[num][i]]==n)
{
ans *= prime[i];
ans %= mod;
}
}
}
}
signed main()
{
ans = 1;
get_prime();
cin >> n >> m;
forn (i,n)
{
int x;
cin >> x;
divide(i, x);
}
forn (i,m)
{
int x,y;
cin >> x>>y;
divide(x,y);
cout << ans << endl;
}
// int stopp;
// cin >> stopp;
}