日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[贪心专题]CF549G,CF351E,CF226D,CF1276C,CF1148E,CF798D

發布時間:2023/12/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [贪心专题]CF549G,CF351E,CF226D,CF1276C,CF1148E,CF798D 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • T1:CF1276C Beautiful Rectangle
    • title
    • solution
    • code
  • T2:CF226D The table
    • title
    • solution
    • code
  • T3:CF549G Happy Line
    • title
    • solution
    • code
  • T4:CF798D Mike and distribution
    • title
    • solution
    • code
  • T5:CF351E Jeff and Permutation
    • title
    • solution
    • code
  • T6:CF1148E Earth Wind and Fire
    • title
    • solution
    • code

T1:CF1276C Beautiful Rectangle

title

solution

保證不重復,我們就按對角線這樣填下去就可以了,這個很好想到
但注意行,列的變換不要這么寫,因為可能是特殊的正方形

r = ( r + 1 ) % row; c = ( c + 1 ) % col;

接下來返回考慮怎樣確定這個矩陣的大小row,colrow,colrow,col,要求row<=colrow<=colrow<=col
我們可以暴力枚舉rowrowrow
也就是說每一個數的最多出現次數要求一定小于等于rowrowrow,不然肯定有一行會有重復數字
然后我們把這些數字出現次數加起來,就能計算出列
注意在判斷矩陣大小的時候必須row?colrow*colrow?col來判斷,不能單純按統計的數字最多出現次數
因為不一定能整除rowrowrow,所以有些數不一定達到了上限的

code

#include <cmath> #include <cstdio> #include <vector> #include <algorithm> using namespace std; #define MAXN 400005 vector < pair < int, int > > g; vector < vector < int > > ans; vector < int > num; int n, row, col; int a[MAXN], b[MAXN], cnt[MAXN];int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ )scanf( "%d", &a[i] ), b[i] = a[i];sort( a + 1, a + n + 1 );int m = unique( a + 1, a + n + 1 ) - a - 1;for( int i = 1;i <= n;i ++ ) b[i] = lower_bound( a + 1, a + m + 1, b[i] ) - a;for( int i = 1;i <= n;i ++ ) cnt[b[i]] ++;for( int i = 1;i <= m;i ++ ) g.push_back( make_pair( cnt[i], i ) );sort( g.begin(), g.end() );int now = 0;for( int i = 1;i <= sqrt( n );i ++ ) {int temp = 0;for( int j = 0;j < g.size();j ++ )temp += min( g[j].first, i );if( temp / i < i ) continue;else if( temp / i * i > now ) now = temp / i * i, row = i, col = temp / i;}printf( "%d\n%d %d\n", row * col, row, col );reverse( g.begin(), g.end() );for( int i = 0;i < g.size();i ++ ) {for( int j = 1;j <= min( g[i].first, row );j ++ )num.push_back( g[i].second );}ans.resize( row );for( int i = 0;i < row;i ++ ) ans[i].resize( col );int r = 0, c = 0;for( int i = 0;i < num.size();i ++ ) {ans[r][c] = num[i];r ++, c ++;if( r == row ) r = 0, c -= row - 1;if( c < 0 ) c += col;if ( c >= col ) c -= col;}for( int i = 0;i < row;i ++ ) {for( int j = 0;j < col;j ++ )printf( "%d ", a[ans[i][j]] );printf( "\n" );}return 0; }

T2:CF226D The table

title

solution

本質就是個暴力
對于總和小于零的每一行,每一列都進行取反操作即可
當某一行或某一列操作次數為偶數的時候,其實相當于是無效操作,最后輸出答案的時候判掉即可
為什么這么暴力就可以?——因為我們限制了操作的總次數極限就是1e61e61e6
把每一行和每一列的和加起來等于整個矩陣的總和的兩倍,值域[?4e6,4e6][-4e6,4e6][?4e6,4e6]
每次取反至少是?1=>1-1=>1?1=>1,整個矩陣總和的兩倍至少增加444,當和無法再增加的時候就是每一行每一列都大于零

code

#include <cstdio> #include <vector> using namespace std; #define MAXN 105 vector < int > r, c; int n, m; int row[MAXN], col[MAXN], visr[MAXN], visc[MAXN]; int a[MAXN][MAXN];int main() {scanf( "%d %d", &n, &m );for( int i = 1;i <= n;i ++ )for( int j = 1;j <= m;j ++ ) {scanf( "%d", &a[i][j] );row[i] += a[i][j];col[j] += a[i][j];}while( 1 ) {bool flag = 1;for( int i = 1;i <= n;i ++ )if( row[i] < 0 ) {visr[i] ++;row[i] = - row[i];for( int j = 1;j <= m;j ++ )col[j] -= ( a[i][j] << 1 ), a[i][j] = - a[i][j];flag = 0;break;}for( int i = 1;i <= m;i ++ ) if( col[i] < 0 ) {visc[i] ++;col[i] = - col[i];for( int j = 1;j <= n;j ++ ) row[j] -= ( a[j][i] << 1 ), a[j][i] = - a[j][i];flag = 0;break;}if( flag ) break;}for( int i = 1;i <= n;i ++ )if( visr[i] & 1 ) r.push_back( i );for( int i = 1;i <= m;i ++ )if( visc[i] & 1 ) c.push_back( i );printf( "%d", r.size() );for( int i = 0;i < r.size();i ++ )printf( " %d", r[i] );printf( "\n%d", c.size() );for( int i = 0;i < c.size();i ++ )printf( " %d", c[i] );return 0; }

T3:CF549G Happy Line

title

solution

非常巧的一個點——對于第iii個數,不管它以后的位置在哪,它原來的下標iii值與valvalval的和是個定值
所以貪心就想到總和越大的越應該往后放
這樣才有可能不減
如果有一個數iii的總和大于最后一個數的總和且在前面某個位置,那么數iii的值就等于總和減去現在的下標,本來值就比最后一個大,減去的又比最后一個小,自然就不可能成為不減序列

code

#include <cstdio> #include <algorithm> using namespace std; #define MAXN 200005 struct node {int val, id; }v[MAXN]; int n;bool cmp( node x, node y ) {return x.val + x.id < y.val + y.id; }int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ )scanf( "%d", &v[i].val ), v[i].id = i;sort( v + 1, v + n + 1, cmp );for( int i = 1;i <= n;i ++ )if( v[i].id + v[i].val == v[i - 1].id + v[i - 1].val )return ! printf( ":(" );else if( i > v[i].id + v[i].val ) return ! printf( ":(");for( int i = 1;i <= n;i ++ )printf( "%d ", v[i].id + v[i].val - i );return 0; }

T4:CF798D Mike and distribution

title

solution

2?∑i=1xa[p[i]]>∑j=1na[j],2?∑i=1xb[p[i]]>∑j=1nb[j]2*\sum_{i=1}^xa[p[i]]>\sum_{j=1}^na[j],2*\sum_{i=1}^xb[p[i]]>\sum_{j=1}^nb[j]2?i=1x?a[p[i]]>j=1n?a[j],2?i=1x?b[p[i]]>j=1n?b[j]
不管是aaa還是bbb數組,都減去一倍已選的數
其實最后的要求都轉化為了,a,ba,ba,b數組已選的數的和要大于沒選的數的和
?n2?+1\lfloor \frac{n}{2}\rfloor+1?2n??+1這個特別要求入手
考慮分奇偶討論
n=2kn=2kn=2k
aaa的從大到小排序,并兩兩分組
第一組的全選上,之后的每一組選擇bbb較大的一個
接下來證明這個算法的正確性
我們每一組都選的bbb較大的一個,自然可以壓制另一個的bbbbbb的要求已經達到
那么aaa怎么辦呢?
如果較大的bbbaaa也較大,那自然更好,甭考慮
如果是較小的aaa,也不用害怕,因為我們第一組的兩個aaa都選了
它們一定大于這一組里面較大的aaa,可以壓制
那么后面遇到類似情況怎么辦,最大的兩個aaa已經用了,沒關系
兩個aaa用了,一定解救出前面較大的某些(個)aaa,拿來壓制現在的aaa
就這么一個一個壓制下去,最后讓aaa也達到要求
奇數同理可得,不再重復

code

#include <cstdio> #include <algorithm> using namespace std; #define MAXN 100005 struct node {int a, b, id; }v[MAXN]; int n;bool cmp( node x, node y ) {return x.a > y.a; }int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ )scanf( "%d", &v[i].a ), v[i].id = i;for( int i = 1;i <= n;i ++ )scanf( "%d", &v[i].b );sort( v + 1, v + n + 1, cmp );printf( "%d\n", ( n >> 1 ) + 1 );if( n % 2 ) {printf( "%d ", v[1].id );for( int i = 2;i <= n;i += 2 )if( v[i].b > v[i + 1].b ) printf( "%d ", v[i].id );else printf( "%d ", v[i + 1].id );}else {printf( "%d %d ", v[1].id, v[2].id );for( int i = 3;i <= n;i += 2 )if( v[i].b > v[i + 1].b ) printf( "%d ", v[i].id );else printf( "%d ", v[i + 1].id );}return 0; }

T5:CF351E Jeff and Permutation

title

solution

考慮數a,ba,ba,b,且∣a∣>∣b∣|a|>|b|a>b
aaa+++
如果bbbaaa前面,不管bbb±±±都不會有逆序對
如果bbbaaa后面,不管bbb±±±都會有逆序對
aaa?-?
如果bbbaaa前面,不管bbb±±±都不會有逆序對
如果bbbaaa后面,不管bbb±±±都會有逆序對

我們發現,逆序對的產生只與兩個數的相對位置以及較大數的正負有關

所以我們只需要考慮對于下標為iii的數,前面絕對值比他小的有多少個,后面比他小的有多少個,取個minminmin即可
至于比他大的數自然是交個比他大的數來管他們之間是否會有逆序對,不管這個數取正取負,逆序對都在較大數的決定上
所以彼此是相互獨立的,不會造成影響

那么兩個數的絕對值一樣的時候呢?這個時候的正負不就有影響了嗎?
所以我們該定義一個dp[i][j]:dp[i][j]:dp[i][j]:iii個數有jjj個為?-?,然后進行轉移
其實并不需要,可以證明絕對值一樣的數一定會是前面一段全選負后面一段全是正
假設下標i<ji<ji<j∣a[i]∣=∣a[j]∣|a[i]|=|a[j]|a[i]=a[j]
如果iii選了正,意味著數列[1,i)[1,i)[1,i)個絕對值比iii小的個數多于(i,n](i,n](i,n]的個數
那么jjj而言,前面的數已經包含了[1,i)[1,i)[1,i),還多加了一段(i,j)(i,j)(i,j),那么前面絕對值小于它的數個數只會增加(不變)不會減小,后面(j,n](j,n](j,n]則只會減小(不變)不會增大
所以是不會彼此之間產生逆序對的,按照上面每個數獨立判斷的做法做即可

code

#include <cmath> #include <cstdio> #include <iostream> using namespace std; #define MAXN 2005 int n, ans; int p[MAXN];int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ )scanf( "%d", &p[i] );for( int i = 1;i <= n;i ++ ) {int Left = 0, Right = 0;for( int j = 1;j < i;j ++ )if( fabs( p[i] ) <= fabs( p[j] ) ) continue;else Left ++;for( int j = i + 1;j <= n;j ++ )if( fabs( p[i] ) <= fabs( p[j] ) ) continue;else Right ++;ans += min( Left, Right );}printf( "%d", ans );return 0; }

T6:CF1148E Earth Wind and Fire

title

solution

很常規的貪心思想,按值排序后,然后下標一一對應,即s[i]s[i]s[i]負責成為t[i]t[i]t[i]
然后我們從最大的開始往下判斷,要知道sss一定先把多余的可以傳遞的傳遞給臨近的
因為如果iii把多余的分給離他很遠的s[j]s[j]s[j],則s[j]<=s[i+1]s[j]<=s[i+1]s[j]<=s[i+1]
就算加上了s[i]s[i]s[i]給的xxxs[j],s[i+1]s[j],s[i+1]s[j],s[i+1]之間的差距也不如將xxx分給s[i+1]s[i+1]s[i+1]
差距越大能傳遞的ddd越大
同時傳遞后要保證s[i]>=t[i]s[i]>=t[i]s[i]>=t[i],當循環到某一個數后,發現他的s<ts<ts<t,則無解
因為我們從大到小一一幫扶過來
此時的數一定接受了比他大的所有的數多出來的t[]?s[]t[]-s[]t[]?s[]
全加上也沒到要求
后面的數也幫不了它,因為s[該數]>=s[后面的數]s[該數]>=s[后面的數]s[]>=s[],無法進行轉移

code

#include <cstdio> #include <vector> #include <algorithm> using namespace std; #define MAXN 300005 #define int long long struct node {int val, id; }s[MAXN], t[MAXN]; struct noded {int l, r, val;noded( int L, int R, int V ) {l = L, r = R, val = V;} }; vector < noded > ans; int n, sums, sumt;bool cmp( node x, node y ) {return x.val > y.val; }signed main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ ) {scanf( "%d", &s[i].val );s[i].id = i, sums += s[i].val;}for( int i = 1;i <= n;i ++ ) {scanf( "%d", &t[i].val );t[i].id = i, sumt += t[i].val;}if( sums != sumt ) return ! printf( "NO" );sort( s + 1, s + n + 1, cmp );sort( t + 1, t + n + 1, cmp );int last = 1;for( int i = 1;i <= n;i ++ ) {if( s[i].val < t[i].val ) return ! printf( "NO" );while( s[i].val > t[i].val ) {while( t[last].val <= s[last].val ) last ++;int temp;temp = min( t[last].val - s[last].val, s[i].val - t[i].val );temp = min( temp, ( s[i].val - s[last].val ) >> 1 );s[i].val -= temp, s[last].val += temp;ans.push_back( noded( s[last].id, s[i].id, temp ) );}}printf( "YES\n%d\n", ans.size() );for( int i = 0;i < ans.size();i ++ )printf( "%lld %lld %lld\n", ans[i].l, ans[i].r, ans[i].val );return 0; }

總結

以上是生活随笔為你收集整理的[贪心专题]CF549G,CF351E,CF226D,CF1276C,CF1148E,CF798D的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。