iwtgm-35
A.
把给定坐标的同一行同一列的每个数都输出(除本身)
void solve() {
char c;
int d;
cin>>c>>d;
for(int i=1;i<=8;i++){
if(i==d)continue;
cout<<c<<i<<endl;
}
for(int i=0;i<=7;i++){
char tmp=(char)('a'+i);
if(tmp==c)continue;
cout<<tmp<<d<<endl;
}
}
B.
字符串模拟,用deque较为方便,大小写字母分开存(同时存下下标)
最后合并放入vector排序,输出
deque<pair<int,char>>low,up;
void solve() {
string s;cin>>s;
for(int i=0;i<s.size();i++){
if(s[i]=='b'){
if(low.size()){
low.pop_back();
}
}else if(s[i]=='B'){
if(up.size()){
up.pop_back();
}
}else if(s[i]>='a'&&s[i]<='z'){
low.push_back({i,s[i]});
}else if(s[i]>='A'&&s[i]<='Z'){
up.push_back({i,s[i]});
}
}
vector<pair<int,char>>v;
while(low.size()){
v.push_back(low.front());low.pop_front();
}
while(up.size()){
v.push_back(up.front());up.pop_front();
}
sort(v.begin(),v.end());
for(int i=0;i<v.size();i++){
cout<<v[i].second;
}
cout<<endl;
}
C.
不同的可以两两消除,那么我们关心相同数量最多的
如果最大数比其他的数量都多,那么一定会剩下最大数-其他数量
若小等于其他数量,因为相同数最大的已经挑出来了,其他相同也可以与最大抵消,可以优先让其他数先两两抵消
奇数一定会剩下一个(因为两两消除)
void solve() {
int n;cin>>n;
string s;cin>>s;
vector<int>v(30);
int ma=-inf;
for(int i=0;i<s.size();i++){
int tmp=s[i]-'a';
v[tmp]++;
ma=max(ma,v[tmp]);
}
int other=s.size()-ma;
if(ma<=other){
if(s.size()%2==0){
cout<<0<<endl;
return ;
}else {
cout<<1<<endl;
return ;
}
}else{
cout<<ma-other<<endl;
}
}
D.
二分答案,二分确实是个好东西
重点是更新区间,往左跳、往右跳,和线段端点取小
int n, l[N], r[N];
bool check(int k) {
int L = 0, R = 0;
for (int i = 1; i <= n; i++) {
int jump_l = L - k, jump_r = R + k;
if (jump_l > r[i] || jump_r < l[i]) return false;
L = max(jump_l, l[i]), R = min(jump_r, r[i]);
}
return true;
}
void solve() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> l[i] >> r[i];
}
int L = 0, R = 1e9, ans = -1;
while (L <= R) {
int mid = (L + R) / 2;
if (check(mid)) {
ans = mid;
R = mid - 1;
} else {
L = mid + 1;
}
}
cout << ans << endl;
}
E.
首先每一位不能有进位
那么每一位对应的三个数相加等于n的对应位的数
数字的每一位都是独立的,用乘法原理
#define int long long
map<int,int>mp;
void solve() {
for(int i=0;i<=9;i++){
for(int j=0;j<=9;j++){
for(int k=0;k<=9;k++){
mp[i+j+k]++;
}
}
}
int t;cin>>t;
while(t--){
int n;cin>>n;
ll ans=1;
while(n){
int tmp=n%10;
ans*=mp[tmp];
n/=10;
}
cout<<ans<<endl;
}
}
F.
可知两种操作都不会改变元素的相对顺序
把它看成一个环,若存在一个起点和一个终点,起点到终点是非递减的,并且囊括了所有点,那么这个序列是可行的
现在考虑操作次数
分类讨论顺逆时针
顺时针:
一种方法:就是把起点及以后的点都放到前面去,操作次数就是起点及起点以后的点的个数
另一种方法:先翻转,把终点及终点后的数都放到前面,最后再翻转一次
取两种方法的操作次数的最小值
逆时针:
可以先翻转成顺时针,按照顺时针的方法做
区别在于第一种方法要加上翻转的一次操作
第二种方法只+1,(在顺时针的时候+2),因为最开始已经+1
可以手玩模拟一个样例就能得知
void solve() {
int n,t,q;
cin>>n;
vector<int>a(n);
for(auto &i:a)cin>>i;
t=*min_element(a.begin(),a.end());
q=*max_element(a.begin(),a.end());
int res=inf;
for(int i=0,f=1;i<n;i++){
if(a[i]!=t)continue;
if(a[(i-1+n)%n]!=q)continue;
f=1;
for(int j=1;j<n&&f;j++){
if(a[(i+j)%n]>=a[(i+j-1)%n])continue;
f=0;
}
if(f)res=min(res,min((n-i)%n,i+2));
break;
}
reverse(a.begin(),a.end());
for(int i=0,f;i<n;i++){
if(a[i]!=t)continue;
if(a[(i-1+n)%n]!=q)continue;
f=1;
for(int j=1;j<n&&f;j++){
if(a[(i+j)%n]>=a[(i+j-1)%n])continue;
f=0;
}
if(f)res=min(res,min(i+1,(n-i)%n+1));
break;
}
if(res==inf){
cout<<-1<<endl;
}
else cout<<res<<endl;
}
G.
改变第 i 盏灯的状态同时也会改变第 i盏灯的状态,所以尝试从 i向 ai 连一条有向边
n个点,n条边,基环树
对于那些状态为1且入度为0的点u,必须要对第u盏灯进行一次操作将其状态变为0
因此可以先对基环树进行拓扑排序,把挂在环上的链先处理完,最后再处理环。
遍历环上的每一个点并统计状态为1的点的数量,如果这个数量是奇数那么无解(因为每次都会同时改变两盏灯的状态,因此状态为1的点的数量也会改变偶数次,即永远不会变成偶数)。否则一定可以将环上点的状态都变成0.
容易知道在任意方案中每个点要么被改变一次,要么不改变。因此只需选择环中的一个点,对两种情况都模拟一边,选择改变次数最小的方案即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
string s;
int ne[N], deg[N];//与i相连的一条边的另一点,入度
queue<int>q;
void solve() {
int n;
cin>>n>>s;s=" "+s;
memset(deg, 0, n + 10 << 2);
for (int i = 1; i <= n; i++) {
int x;
cin>>x;
ne[i] = x;
deg[x]++;
}
for (int i = 1; i <= n; i++) {//拓扑
if (!deg[i]) q.push(i);
}
vector<int> ans;
while (q.size()) {
int u = q.front();q.pop();
if (s[u] & 1) {
s[u] ^= 1;
s[ne[u]] ^= 1;
ans.push_back(u);
}
if (--deg[ne[u]] == 0) q.push(ne[u]);
}
for (int i = 1; i <= n; i++) {
if (deg[i]) {//环上
int u = i, cnt = 0, sum = 0;
while (deg[u]) {
deg[u] = 0;
cnt++; // 统计环中点的数量
sum += s[u] & 1; // 统计状态为1的点的数量
u = ne[u];
}
if (sum & 1) { // sum是奇数则无解
printf("-1\n");
return;
}
vector<int> p1, p2;
u = i; // 任选环中一个点
for (int j = 0, t = 0; j < cnt; j++) { // 这个点改变一次
if (!j || (t ^ s[u]) & 1) {//一条边的两个点都是1,只需改变第一个点
t = 1; //若一条边的1个点是0,一个点是1,则要改变2次
p1.push_back(u);
}
else {
t = 0;
}
u = ne[u];
}
u = i;
for (int j = 0, t = 0; j < cnt; j++) { // 这个点不改变
if (j && (t ^ s[u]) & 1) {
t = 1;
p2.push_back(u);
}
else {
t = 0;
}
u = ne[u];
}
if (p1.size() > p2.size()) p1.swap(p2); // 选择改变次数最小的方案
for (auto &x : p1) {
ans.push_back(x);
}
}
}
printf("%d\n", ans.size());
for (auto &x : ans) {
printf("%d ", x);
}
printf("\n");
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}