目录
Flip Game 0星
题意就是问你有没有可能把棋子翻成全黑或全白,翻某个棋子的同时也会让这个棋子的上下左右一起翻。
枚举+贪心
当某一层再怎么翻也不能达到全黑或者全白的时候,只能翻你要翻的棋子的同列的下一行的棋子,所以可以通过二进制枚举第一层可能翻棋子的方案,再通过翻它的下一层把这一层需要翻的棋子翻过去,以此类推一层一层的让他满足全白或者全黑的要求,因为前面的都满足要求了,就看最后一层有没有全白或者全黑,就可以判断方法是否可行。
另开一个数组,用来存这个棋子到底有没有翻,判断一个棋子有没有被翻过去,可以通过判断自身点和其他能影响到这个点是否有没有翻来了判断,点的和取模。
AC代码
#include <iostream>
#include <memory.h>
using namespace std;
int flip[4][4];
char getflip[4][4];
int swapflip[4][4];
int MOVE[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
int sum = 0;
int possible = 0;
bool rightindex(int i,int j){
return 0<=i && i <4 && 0<=j && j < 4;
}
bool check(int i,int j,int key){
int i1,j1;
int num = swapflip[i][j];
num+=flip[i][j];//要把自己的那个点也要加进去
for(int w = 0;w < 4;w++){
i1 = i + MOVE[w][0];
j1 = j + MOVE[w][1];
if(rightindex(i1,j1))
num+=flip[i1][j1];
}
if(num%2 == key)
return true;
else return false;
}
void find(int key){
int sum1,flag;
for(int n = 0;n <=15;n++){//二进制枚举
memset(flip,0,sizeof(flip));
sum1 = 0;
flag = 1;
for(int j = 0;j < 4;j++){
flip[0][j] = ( n>>(3-j) )&1;
sum1+=flip[0][j];
}
for(int i = 1;i < 4;i++){
for(int j = 0;j < 4;j++){
if(!check(i-1,j,key)){
flip[i][j] = 1;//下方要翻牌
sum1++;
}
}
}
for(int j = 0;j < 4;j++){ //判断是否可以全0或1
if(!check(3,j,key)){
flag = 0;
break;
}
}
if(flag){
if(!possible || sum1 < sum)
sum = sum1;
possible = 1;
}
}
return ;
}
int main(){
for(int i = 0;i < 4;i++){
cin >> getflip[i];
}
for(int i = 0;i < 4;i++){
for(int j = 0;j < 4;j++)
if(getflip[i][j] == 'w')
swapflip[i][j] = 0;
else swapflip[i][j] = 1;
}
//找黑,找白
find(1);
find(0);
if(!possible)
cout << "Impossible" << endl;
else cout << sum << endl;
//system("pause");
return 0;
}
Subsequence 0星
尺取
#include <iostream>
using namespace std;
long long num[100010];
long long sum[100010];
int main(){
long long t,l,r,s,len;
cin >> t;
long long ans;
int flag = 0;
for(int k = 0;k < t;k++){
cin >> len >> s;
for(int i = 1;i <= len;i++){
cin >> num[i];
sum[i] = sum[i-1] + num[i];
}
flag = 0;
l = 0;
r = 1;
ans = 100010;;
for(;r <= len;){
if(sum[r]-sum[l]>=s){
ans = min(ans,r-l);
l++;
flag = 1;
}else r++;
}
if(flag)
cout << ans << endl;
else cout << 0 << endl;
}
//system("pause");
return 0;
}
Quasi Binary 0星
贪心:拆成的每个数字尽可能的大,把原数的每一位拆分为n个1;最小组成个数是原数中各个位中的最大数
#include <iostream>
using namespace std;
int num[10];
int main(){
int n;
cin >> n;
int len;
int ans = 0;
for(int i = 0;;i++){//求最少用几个数组成
num[i] = n%10;
ans = max(ans,num[i]);
n/=10;
if(!n){
len = i;
break;
}
}
int flag = 1,flag2;
cout << ans << endl;
while(flag){//输出这些数
flag = 0;
flag2 = 0;
for(int i = len;i>=0;i--){
if(num[i]){
cout << 1;
flag2 = 1;
if(--num[i]>0)
flag = 1;
}else if(flag2) cout << 0;
}
cout << " ";
}
//system("pause");
return 0;
}
Protecting the Flowers 1星
贪心:假设序列的前面部分已经按最优解,有两只牛A、B,当AB排序别BA,排序时把AB牛之间的关系求出来,按这个关系sort排序即可,代码中使用的是推出来的除法式子,把除法式子转换为乘法更好。
AC代码
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct Node{
int ti;
int di;
double varth;
}cow;
cow cc[1000000];
int sum[1000000];
bool cmp(cow a,cow b){
return a.varth < b.varth;
}
int main(){
int n;
cin >> n;
for(int i = 0;i < n;i++){
cin >> cc[i].ti >> cc[i].di;
cc[i].varth = (double)cc[i].ti/(double)cc[i].di;
}
sort(cc,cc+n,cmp);
sum[0] = cc[0].ti;
for(int i = 1;i < n;i++){
sum[i] = sum[i-1] + cc[i].ti;
}
long long cost = 0;
for(int i = 1;i < n;i++){
cost+=sum[i-1]*cc[i].di*2;
}
cout << cost << endl;
//system("pause");
return 0;
}
校门外的树 1星
法1开个数组初值赋值为1,把给的区间用memset赋值为0即可,最后扫描数组。
代码略
法2 差分
AC代码
#include<iostream>//差分
using namespace std;
int d[10002];
int main(){
int L,m;
int l,r;
d[0] = 1;
cin >> L >> m;
for(int i = 0;i < m;i++){
cin >> l >> r;
d[l] -= 1;
d[r+1]+= 1;
}
int sum = 0;
if(d[0]>0) sum++;
for(int i = 1;i <= L;i++){
d[i] = d[i-1] + d[i];
if(d[i] > 0)
sum++;
}
cout << sum << endl;
//system("pause");
return 0;
}
法3 按每个移走的区间的左端从小到大排序,把重叠区间和并(离散化?) 如果给的初始树的区间很大,差分就不能用了。
AC代码
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct Node{
int left;
int right;
}tree;
tree tt[100];
bool cmp(tree a,tree b){
return a.left < b.left;
}
int main(){
int L,m;
cin >> L >> m;
for(int i = 0;i < m;i++){
cin >> tt[i].left >> tt[i].right;
if(tt[i].left >L)
tt[i].left = L;
if(tt[i].right > L)
tt[i].right = L;
}
sort(tt,tt+m,cmp);
int sum = 0,start = 0,end = 0;
for(int i = 1;i < m;i++){
if(tt[end].right >= tt[i].left){//区间覆盖
if(i == m-1){//端点
end = tt[end].right > tt[i].right ? end:i;
sum += (tt[end].right - tt[start].left+1);
break;
}
end = tt[end].right > tt[i].right ? end:i;
continue;
} else{//区间不覆盖
sum+= (tt[end].right - tt[start].left +1);
start = i;
end = i;
}
if(i == m-1){
sum += (tt[end].right - tt[start].left+1);
break;
}
}
cout << L- sum + 1<< endl;
//system("pause");
return 0;
明明的随机数 1星
#include <iostream>
#include <cstdbool>
using namespace std;
bool num[1002];
int main(){
int n;
cin >> n;
int x;
int sum = 0;
for(int i = 0;i < n;i++){
cin >> x;
num[x] = num[x]? true :(sum++,true);
}
cout << sum << endl;
for(int i = 0;i <= 1000;i++)
if(num[i])
cout << i << " ";
//system("pause");
return 0;
}
[HNOI2003]激光炸弹 2星
二维差分+枚举 把目标当做点来处理 也就num[i][j]
#include <iostream>
using namespace std;
int num[5010][5010];
int main(){
int n,r;
int x,y,v;
int sum = 0;
int ans = 0;
cin >> n >> r;
for(int i = 0;i < n;i++){
cin >> x >> y >> v;
num[x+1][y+1] = v;
}
for(int i = 1;i <= 5000;i++)
for(int j = 1;j <= 5000;j++)
num[i][j] = num[i][j] + num[i-1][j] + num[i][j-1] -num[i-1][j-1];
for(int i = 1;i <= 5000;i++){
for(int j = 1;j <= 5000;j++){
x = i+r-1 > 5000? 5000: i+r-1;
y = j+r-1 > 5000? 5000: j+r-1;
sum = num[x][y] - num[i-1][y] - num[x][j-1] + num[i-1][j-1];
ans = sum > ans ? sum : ans;
}
}
cout << ans << endl;
//system("pause");
return 0;
}
铺地毯 2星
贪心 对地毯按从大到小判断点是否在地毯上,如果在就是答案
#include <iostream>
using namespace std;
int main(){
int n;
int num[10002][4];
cin >> n;
int x,y;
for(int i = 1;i <= n;i++)
cin >> num[i][0] >> num[i][1] >> num[i][2] >> num[i][3];
cin >> x >> y;
int flag = 0;
for(int i = n;i>0;i--){
if(num[i][2] + num[i][0] >= x && x >=num[i][0])
if(num[i][3] + num[i][1] >= y && y >=num[i][1]){
flag = 1;
cout << i;
break;
}
}
if(!flag)
cout << -1;
return 0;
}
纪念品分组 2星
贪心+双指针
排序后,让价格大的尽可能和多个便宜的合成一组,只考虑便宜的和便宜的不行。比如样例 20 30 50 50 70 80 每组上限100 小的优先为4组,小大结合为3组
代码
#include <iostream>
#include <algorithm>
using namespace std;
int main(){
int n;
int sum;
int num[30010];
int head,last;
cin >> sum >> n;
for(int i = 0;i < n;i++){
cin >> num[i];
}
sort(num,num+n);
head = 0;
last = n-1;
int ans = 0;
int sum2 = 0;
while(head <= last){
sum2 = num[last];
while(sum2 + num[head] <= sum && head <last){
sum2+=num[head];
head++;
}
ans++;
last--;
}
cout << ans;
return 0;
}
回文日期 2星
枚举 可以枚举 月和日 得到对应回文,再判断回文是否合法,注意判断二月29闰年
AC代码
#include <iostream>
using namespace std;
int key[8] = {1,10,100,1000,10000,100000,1000000,10000000};
int month[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31};
int d1,d2,ans;
void checkandcreat(int n){
if(n%100 == 29){
if((n/10000)%100 == 0 && (n/10000)%400 !=0)//年份整百
return ;
else if((n/10000)%4)//年份不是整百
return ;
}
for(int i = 0;i < 4;i++)
n= n + ((n/key[i])%10) * key[7-i];
if(d1<=n && n<=d2)
ans++;
return ;
}
int main(){
cin >> d1 >> d2;
int num;
for(int i = 1;i <=12; i++){
for(int j = 1; j <= month[i];j++ ){
num = i*100 + j;
checkandcreat(num);
}
}
cout << ans;
return 0;
}
拼数 2星
贪心 通过排序 cmp:两个数替换位置看哪个大
AC代码
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
typedef struct Node{
string s;
}NUM;
NUM N[21];
string s1,s2;
bool cmp(NUM a,NUM b){
s1 = a.s + b.s;
s2 = b.s + a.s;
return s1 > s2;
}
int main(){
int n;
cin >> n;
int len;
int key;
for(int i = 0;i < n;i++){
cin >> N[i].s;
}
sort(N,N + n,cmp);
for(int i = 0;i < n;i++){
cout << N[i].s;
}
return 0;
}
毒瘤xor 2星
贪心,每个二进制位单独判断,判断祝各位是1得到总和大,还是0的大
AC代码
#include <iostream>//前缀和 加异或
using namespace std;
int num[100010][32];
void fun(int i,int n){
for(int t = 31;t > 0;t--){
num[i][t] = n%2;
n/=2;
}
}
int main(){
int n;
int x;
int l,r;
int t;
int key;
cin >> n;
for(int i = 1;i <= n;i++){
cin >> x;
fun(i,x);
}
for(int i = 1;i < 32;i++){
for(int j = 1;j <= n;j++)
num[j][i] += num[j-1][i];
}
cin >> t;
for(int i = 0;i < t;i++){
cin >> l >> r;
x = 0;
key = 1;
for(int t = 31;t > 0;t--){//输出较小的能为0 就为0
if((num[r][t] - num[l-1][t])*2 < r -l+1 ){// <
x +=key;
}
key*=2;
}
cout << x << endl;
}
return 0;
}
字符串 2星
模拟,写个数组用来判断这个字母是否已经存了,存了几个
#include <iostream>
#include <cstring>
using namespace std;
char s[1000100];
int num[26];
bool check(void){
for(int i = 0;i < 26;i++){
if(!num[i])
return false;
}
return true;
}
void incre(int n){
if(0 <= n-'a' && n - 'a'< 26)
num[n -'a']++;
}
void decre(int n){
if(0 <= n -'a' && n - 'a'< 26)
num[n -'a']--;
}
int main(){
int ans = 2000000;
int head = 0,last = 0;
int len = 0;
int getted = 0;
cin >> s;
len = strlen(s);
for(int i = 0;i < 26;i++){
incre(s[i]);
}
if(check()){
cout << 26;
return 0 ;
}
for(last = 26;last < len;last++){
incre(s[last]);
if(check()){//如果已经满了
while(check()){//更新为子串得最优子串
decre(s[head]);
head++;
}
incre(s[--head]);
if(last - head + 1 < ans){
ans = last - head + 1;
}
}
}
cout << ans;
return 0;
}
数学考试 2星
前缀和 + 枚举 求i-n最大连续k个数之和 ,然后枚举区间
AC代码
#include <iostream>
using namespace std;
long long num[400020];
long long maxk[400020];
long long max(long long a,long long b){
return a > b?a:b;
}
int main(){
int n,k,t;
long long ans;
cin >> t;
for(int w = 0;w < t;w++){
cin >> n >> k;
for(int i = 1;i <= n;i++){
cin >> num[i];
num[i] += num[i-1];
}
maxk[n-k+2] = -100000000000;//可能都是负数
for(int i = n-k+1;i > 0;i--){//i - n最大连续K个数之和
maxk[i] = max(maxk[i+1],num[i+k-1] - num[i-1]);
}
ans = -10000000000000;
for(int i = k;i <= n-k;i++)//边界要处理干净
ans = max(num[i] - num[i - k] + maxk[i+1],ans);
cout << ans << endl;
}
return 0;
}
「土」秘法地震 2星
二维差分 + 枚举 如果矩阵有值就是有建筑物
#include <iostream>
using namespace std;
int num[2000][2000];
int main(){
int n,m,k;
char c;
cin >> n >> m >> k;
for(int i = 1;i <= n;i++){
for(int j = 1;j <=m;j++){
cin >> c;
if(c =='1')
num[i][j] = 1;
else if(num[i][j] == '0')
num[i][j] = 0;
}
}
int ans = 0;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= m;j++){
num[i][j] = num[i][j]+num[i-1][j] + num[i][j-1] - num[i-1][j-1];
}
}
for(int i = k;i <= n;i++){
for(int j = k;j <= m;j++){
if(num[i][j] + num[i-k][j-k] - num[i-k][j] - num[i][j-k])
ans++;
}
}
cout << ans <<endl;
return 0;
}
丢手绢 2星
尺取 小朋友A相邻的小朋友B的隔最远的为A的最远小朋友,或者A最远小朋友的右边
#include <iostream>
using namespace std;
long long num[100020];
int min(int a,int b){
return a>b?b:a;
}
int max(int a,int b){
return a>b?a:b;
}
int main(){
int n;
int ans = 0;
long long len;
cin >> n;
for(int i = 1;i <= n;i++){
cin >> num[i];
num[i]+=num[i-1];
}
for(int i = 0, j = 1; j < n;){
while((num[j] - num[i])*2 < num[n] && j < n)
j++;
if(j < n)
ans = max(ans,max(num[j-1] - num[i],num[n] - num[j] + num[i]));
else ans = max(ans,num[j-1] - num[i]);
i++;
}
ans = max(ans,min(num[n] - num[n-1],num[n-1]));
cout << ans;
return 0;
}
排座椅 3星
贪心 把每对说话人要隔开的通道计数+1,再排序
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct node{
int key;
int warth;
}ct;
ct countx[1020];
ct county[1020];
int min(int a,int b){
return a>b?b:a;
}
bool cmp(ct a,ct b){
return a.warth > b.warth;
}
bool cmp2(ct a,ct b){
return a.key < b.key;
}
int main(){
int n,m,k,l,d;
cin >> m >> n >> k >> l >> d;
int x1,y1,x2,y2;
for(int i = 1;i <= d;i++){
cin >> x1 >> y1 >> x2 >> y2;
if(x1 == x2){
county[min(y1,y2)].warth++;
county[min(y1,y2)].key = min(y1,y2);
}else{
countx[min(x1,x2)].warth++;
countx[min(x1,x2)].key = min(x1,x2);
}
}
sort(countx,countx + m,cmp);
sort(countx,countx + k,cmp2);
sort(county,county + n,cmp);
sort(county,county + l,cmp2);
for(int i = 0;i < k;i++)
cout << countx[i].key << " ";
cout << endl;
for(int i = 0;i < l;i++)
cout << county[i].key << " ";
return 0;
}
国王的游戏 3星
贪心+大数 求出大臣A、B。按AB排序优于按BA排序的不等式cmp,用cmp快排,求排序后最大值即可,乘法和除法的用大数实现
#include <iostream>
#include <algorithm>
#include <string>
#include <memory.h>
using namespace std;
typedef struct NODE{
string left;
string right;
}num;
num minister[1020];
string s3;
string multiplication(string s1,string s2){
int ans[4000];
memset(ans,0,sizeof(ans));
s3 = "";
int len1, len2, i, j;
int index, key;
char c;
len1 = s1.length();
len2 = s2.length();
reverse(s1.begin(),s1.end());
reverse(s2.begin(),s2.end());
for (i = 0; i < len1; i++) //时间复杂度为n*m
{
for (j = 0; j < len2; j++)
{
// printf("%d %d\n",i,num);
ans[i + j] += (s1[i] - '0') * (s2[j] - '0'); //从0开始逆序输出
//ans[index+1] += (num/10);
}
}
//个位为0^十位为2……
for (index = 0; index < len1 + len2 + 10; index++) //循环条件要确保index完全走完数组长度
{
if (ans[index] > 9) //
{
ans[index + 1] += ans[index] / 10;
ans[index] %= 10;
}
}
while (ans[index] == 0 && index > 0) //省去高位
{
index--;
}
while (index >= 0) //逆序输出
{
c = '0' + ans[index];
s3+=c;
index--;
}
return s3;
}
bool cmp(num a,num b){
string s1,s2;
s1 = multiplication(b.right,b.left) ;
s2 = multiplication(a.right,a.left);
if(s1.length() > s2.length())
return true;
if((s1.length() == s2.length()) && s1.compare(s2) > 0)
return true;
return false;
}
string max(string a,string b){
if(a.length() > b.length())
return a;
if(a.length() == b.length() && a.compare(b) >0)
return a;
return b;
}
string division(string s1,string s2)
{
s3 = "";
int ans[4000];
memset(ans,0,sizeof(ans));
int key,key1,len1,len2,i;
len1 = s1.length();
len2 = s2.length();
key = len1 - len2;
if ((key < 0) || (key == 0 && s1.compare(s2) < 0)) //小数除大数
{
s3 = "0";
return s3; //结束处理
}
key1 = key; //key1为原始位差
while (key >= 0) //从最高位开始减,key表示,s1和s2的位差
{
//比较子串
while (s1.compare(len1 - key - len2, len1, s2, 0, len2) < 0 && key >= 0) //给s2加的位差过大,s1<s2
{
if(len1 - key - len2 > 0 && s1[len1 - key -len2 -1] > '0')//s1前面已经有非零位 已经大于
break;
key--; //减小位差
}
if (key < 0) //位差小于0此时s1<s2 不能再减
break;
for (i = len2 - 1; i >= 0; i--) //从低位开始减 key1 = len1 -len2
{
s1[i + key1 - key] = s1[i + key1 - key] - s2[i] + '0';
if (s1[i + key1 - key] < '0') //借位,因为s1>s2所以放心借位
{
s1[i + key1 - key] += 10;
//if(i+key1-key>0)
s1[i + key1 - key - 1] -= 1;
}
}
ans[key]++; //减法次数加1
}
//最多有key1位
while (!ans[key1]) //去掉前置0,逆序存放所以逆序输出
{
key1--;
}
char c;
while (key1 >= 0) //逆序输出商
{
c = ans[key1] + '0';
//printf("%d", ans[key1]);
s3 += c;
key1--;
}
return s3;
}
int main(){
string king;
string ans;
int n;
cin >> n;
cin >> king >> ans;
for(int i = 0;i < n;i++)
cin >> minister[i].left >> minister[i].right;
sort(minister,minister + n,cmp);
ans = division(king,(minister[0].right));
for(int i = 1;i < n;i++){
king = multiplication(king,minister[i-1].left);
ans = max(ans,division(king,minister[i].right));
}
cout << ans;
//system("pause");
return 0;
}
[SCOI2005]扫雷MINE 3星
枚举+检验
枚举第一个空有没有雷,一旦确定,根据第二列的地雷数,就可以确定哪个地方有雷,哪个地方没有雷,把格子填雷后,最后再判断最后一行第二列是统计地雷书是否与题目给出符合。答案 0-2
AC代码
#include <iostream>
using namespace std;
int num[10010][2];
int n;
int MOVE[3] = {-1,1,0};
bool right_index(int i){
return 0 < i && i <=n;
}
int getsum(int i){
int index;
int sum = 0;
for(int j = 0;j < 3;j++){
index = MOVE[j] + i;
if(right_index(index)){
sum += num[index][0];
}
}
return sum;
}
int dfs(int i,int key){
int x = 0;
int ans = 0;
if(i > n){
if(getsum(i-1) == num[i-1][1])
return 1;
else return 0;
}
num[i][0] = key;
x = num[i][1] - getsum(i);
if(x == 1)
ans = dfs(i+1,1);
else if(!x)
ans = dfs(i+1,0);
num[i][0] = 0;//防止影响main的另一个dfs
return ans;
}
int main(){
cin >> n;
for(int i = 1;i <=n;i++)
cin >> num[i][1];
cout << dfs(1,0) + dfs(1,1) << endl;
return 0;
}
起床困难综合症 3星
位运算+ 贪心+ 枚举
对于大于m的二进制位只求0通过防御门的这一位攻击,对于<=m的二进制位求01通过防御门的攻击,由于m不同,不一定<m的每个位都可以取到1如果可以选1但选0更优,那你就选0,之后的低位,选01都无所谓,因为已经确保了攻击力 <=m;
AC代码
#include <iostream>
using namespace std;
char s[200010][3];
int op[200010][32];
int num[32];
int ans[32][2];
long long fn[32];
int main(){
int n,m;
cin >> n >> m;
for(int i = 0; i< n;i++){
scanf("%s %d",s[i],&op[i][31]);
}
int index = 0;
while(m){//低位到高位
num[index] = m%2;
m/=2;
index++;
}
for(int i = 0;i < n;i++){//从低位到高位
index = 0;
while(op[i][31]){
op[i][index] = op[i][31]%2;
op[i][31]/=2;
index++;
}
}
int x,flag = 0;
for(int i = 30;i>=0;i--){//高位到低位求01最后攻击到龙的数据
if(num[i] || flag){
x = 1;
for(int j = 0;j < n;j++){
if(s[j][0] =='A')
x &= op[j][i];
else if(s[j][0] == 'O')
x |= op[j][i];
else x^=op[j][i];
}
ans[i][1] = x;
flag = 1;
}
x = 0;
for(int j = 0;j < n;j++){
if(s[j][0] =='A')
x&=op[j][i];
else if(s[j][0] == 'O')
x|=op[j][i];
else x^=op[j][i];
}
ans[i][0] = x;
}
long long result = 0;
flag = 0;
fn[0] = 1;
for(int i = 1;i < 31;i++){
fn[i] = fn[i-1]*2;
}
for(int i = 30;i >=0;i--){
if(ans[i][0]){//0一定可以取到
result+=fn[i];
if(num[i]){
flag = 1;//后面num[i]即使是0也可以取1
continue;
}
}
else if(num[i] || flag ){//可以取到1
if( ans[i][1])
result += fn[i];
else flag = 1;//不取1
}
}
printf("%lld",result);
return 0;
}
奇♂妙拆分 3星
枚举 判断拆分剩下的数是否已经有了
AC代码
#include <iostream>
#include <cmath>
#include <string.h>
using namespace std;
int num[20];
int len;
bool checkin(int n){
for(int i = 0;i < len;i++){
if(n == num[i])
return false;
}
num[len++] = n;
return true;
}
int main(){
int T;
cin >> T;
int n;
int ans;
int x;
for(int t = 0;t < T;t++){
ans = 1;
len = 0;
cin >> n;
if(n == 1){
cout << 1 << endl;
continue;
}
x = n;
for(int i = 2;i <= sqrt(x);i++){
if(x%i == 0){
if(checkin(i)){//判断是否已经有了这个数
if(checkin(x/i)){//判断拆剩下的数是否重复
ans++;
x/=i;
}
else len--;//x/i重复,checkin(i)家的数要丢掉
}
}
}
ans++;//因为最后拆剩下了一个数
cout << ans << endl;
}
return 0;
}
糖糖别胡说,我真的不是签到题目 3星
差分+思维 差分快速完成对区间的+1操作(发功),然后维护两组i-n的最大能力值max数组,从后往前看如果第i个能力值 < 另一组 max[i+1-n],这个糖糖一定会被消灭。
AC代码
#include <iostream>
using namespace std;
typedef struct node{
int key;
int dif;
}GNODE;
GNODE num[50020];
int d[50020];
//差分快速得到多次对每个不同区间进行操作后的最终结果
int main(){
int n,m,T,ans = 0;
int dist;
cin >> T;
for(int t = 0;t < T;t++){
ans = 0;
cin >> n >> m;
for(int i = 1;i <= n;i++){
cin >> num[i].dif >> num[i].key;
d[i] = num[i].key - num[i - 1].key;
//cout <<"d " << d[i] << endl;
}
for(int i = 1;i <= m;i++){
cin >> dist;
d[1]++;
d[dist + 1]--;
}
for(int i = 1;i <= n;i++) d[i]+=d[i-1];
int max1 = 0,max0 = 0;
for(int i = n;i >= 1;i--){
if(num[i].dif){
if(d[i] >= max0){
ans++;
}
max1 = max(max1,d[i]);
}
else{
if(d[i] >= max1){
ans++;
}
max0 = max(max0,d[i]);
}
}
cout << ans << endl;
}
return 0;
}
「土」巨石滚滚 3星
贪心 冲撞一瞬间-ai稳定冲撞过程如果稳定性X<0 就散架,冲撞结束后+bi的稳定性。
为了使得尽可能的可以完成所有冲撞,要把冲撞结束稳定性增加的障碍物放前面,增加稳定性(如果连稳定性增加到可能的最大都不能完成所有冲撞,那么一定会失败,相反也要用尽可能大的稳定性X来面对大ai障碍物),对于ai < bi的障碍物把ai 从小到大排序,防止一开始就散架.对于ai > bi的障碍物 可以要按bi从大到小排序,可以用AB排序时YES,BA排序时NO的情况来证明。
AC代码
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct Noder{//撞后稳定性增加从小到大排序
//a-b>0的把a小的放前面,
long long a,b,c;// m =6 5 1,4 3
}node;
node num[500010];//要一直朝一个方向去证,比如一直证NO,或者YES,不要一会证YES一会证NO
bool cmp1(node x,node y){
return x.c > y.c;
}
bool cmp2(node x,node y){
return x.a < y.a;
}
bool cmp3(node x,node y){
return x.b > y.b;
}
int main(){
long long T,t,n,m,index;
cin >> T;
int flag = 0;
for(int t = 0;t < T;t++){
cin >> n >> m;
for(int i = 0;i < n;i++){
cin >> num[i].a >> num[i].b;
num[i].c = num[i].b - num[i].a;
}
sort(num,num+n,cmp1);//左闭右开
flag = 0;
for(int i = 0;i < n;i++)
if(num[i].c <0 ){//num[i].c=0的放前面
index = i;
flag = 1;
break;
}
if(flag){
sort(num,num+index,cmp2);
}
else sort(num,num+n,cmp2);
if(flag)
sort(num + index,num + n,cmp3);//!!!!!!!假设AB过BA不过得到cmp3
flag = 0;
for(int i = 0;i < n;i++){
if(m < num[i].a){
cout <<"No"<<endl;
flag = 1;
break;
}
m += (num[i].b - num[i].a);
}
if(!flag)
cout << "Yes" << endl;
}
return 0;
}
矩阵消除游戏 3星
二进制枚举+贪心
k >=n || k >=m意味着可以全选,否则把行枚举选完,就可以贪心的选大的列了。
AC代码
#include <iostream>
#include <algorithm>
using namespace std;
long long num[17][17];
long long c[17];
long long c1[17];
long long r[17];
bool cmp(long long x,long long y){
return x > y;
}
int main(){
long long ans = 0,sum = 0;
int n,m,k;
cin >> n >> m >> k;
for(int i = 0;i < n;i++){
for(int j =0;j < m;j++){
cin >> num[i][j];
r[i]+= num[i][j];
}
}
for(int i = 0;i < m;i++){
for(int j = 0;j < n;j++){
c[i]+=num[j][i];
}
}
if(k >= min(n,m)){
sum = 0;
for(int i = 0;i < n;i++)
sum+=r[i];
cout << sum << endl;
return 0;
}
int t = k;
int x = 0;
int index = 0;
for(int i = 0;i <= (1<<n)-1;i++){
t = k;
x = i;
index = 0;
sum = 0;
for(int j = 0;j < m;j++) c1[j] = c[j];
while(x){
if(x&1){
sum+=r[index];
t--;
for(int j = 0;j < m;j++) c1[j] -= num[index][j];
}
x>>=1;
index++;
}
if(t < 0)
continue;
else if(!t){
ans = max(ans,sum);
}
else{
sort(c1,c1 + m,cmp);
t--;
while(t>=0){
sum+=c1[t];
t--;
}
ans = max(ans,sum);
}
}
cout << ans << endl;
return 0;
}
牛牛的木板 4星
①前缀和 + 尺取(m) + 双指针
②也可以使用队列存放清洗木板位置
AC代码
①
#include <algorithm>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int
* @param m int
* @param a intvector
* @return int
*/
int solve(int n, int m, vector<int>& a) {//前缀和
int index,sum = 0;
for(int i = n; i;i--){
a[i]=a[i-1];
}
a[0] = 0;
for(int i = 2;i <= n;i++){
a[i]+=a[i-1];
}
index = 0;
for(int i = 1;i <= n;i++){
if(a[i]-a[index] + m >= i - index)
continue;
else{
sum = max(sum, i - index-1);
while(a[i]-a[index] + m < i - index){
index++;
}
}
}
sum = max(sum,n - index);
return sum;
}
};
②队列
#include <algorithm>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int
* @param m int
* @param a intvector
* @return int
*/
queue<int> get;
int solve(int n, int m, vector<int>& a) {
int maxnum = 0,sum = 0;
for(int i = 0;i < n;i++){
if(a[i]){
sum++;
}else{
if(get.size() == m){
maxnum = max(maxnum,sum);
sum = i - get.front();
get.pop();
get.push(i);
}else{
get.push(i);
sum++;
}
}
}
maxnum = max(maxnum,sum);
cout << maxnum << endl;
return maxnum ;
}
};