T1 排序
小明班裏一共 𝑁名同 學,小明這次考試的不錯他知道了多少分,以及班級裏的同學一共考了幾分,考試滿分100分,同分數可並列排名,求小明最高可以多少名,最低可以多少名
T2 位運算
給定 𝑁個非負整 數 ,每次你可以選擇兩個數 𝑎,𝑏,,將其中一個數變爲 𝑎 𝑎𝑛𝑑 𝑏,另一個變 成𝑎 𝑜𝑟 𝑏,你可以進行多次操作, 任何時候都可以停止。
T3 最長不下降子序列
給你一個正整數 N,SR希望你統計所有的長度恰好爲n的01序列的最長不下降子之序列之和
T1
題意概括:給出n個人得分總量,給出一個人分數p,求這個人能在在這些人中最高拍多少,最低排多少
這道題好惡心,一開始推了一會兒還很得意以爲又是一道水題(本來就是一道水題),後來發現推錯了。。。
於是又推推推,
1.讓他最高分反正就是讓分的人儘量多(儘量同分能使排名更高,好讓比p低的更多)
2.讓他最低分,就是讓的人儘量多,(比它高一點又不佔太多分數,)
#include<bits/stdc++.h>
using namespace std;
int n,sump,pe,highrnk,lowrnk,mid;
inline void low()
{
int sumyu=(n+1)*pe;
if (sumyu<=sump) {lowrnk=pe+1; return;}
int yu=sumyu-sump;
int bu=yu/n;
int yu1=yu%n;
if (yu1>=1) {lowrnk=pe-bu; return;}
lowrnk=pe-bu-1;
}
inline void high()
{
int sumyu=n*pe;
if (sumyu>=sump) {highrnk=1; return;}
int yu=sump-sumyu;
int bu=yu/(100-n);
int yu1=yu%(100-n);
if (yu1>=1) {highrnk=bu+2; return;}
highrnk=bu+1;
}
int main()
{
scanf("%d%d%d",&pe,&n,&sump);
pe--;
sump-=n;
mid=sump/pe;
low();
high();
if (n==100) highrnk=1;
printf("%d %d",highrnk,lowrnk);
}
對了 p=100分的時候要特判
T2
題意概括:額,我覺得題目講的挺清楚了
首先肯定是每個合併過後的數,二進制1越多越好,那麼我們統計每一個數所有位數上1的個數,因爲,
所以每一位上只要還存在1,肯定就能合併
#include<bits/stdc++.h>
const int maxn=100007;
using namespace std;
long long n,m;
long long tong[maxn];
int main()
{
scanf("%lld",&n);
long long ans=0;
for (long long i=1; i<=n; i++)
{
long long x;
scanf("%lld",&x);
for (long long j=0; j<=20; j++)
if(x&(1<<j)) tong[j]++;
}
for (long long i=1; i<=n; i++)
{
long long x=0;
for (long long j=0; j<=20; j++)
if (tong[j])
{
tong[j]--;
x+=(1<<j);
}
ans+=x*x;
}
printf("%lld\n",ans);
}
T3
題意概括:如題,長度爲n的所有01串中最長不下降子序列長度之和
:我們不妨考慮這個狀態 𝑓[𝑖][𝑗][𝑘]表示長度爲 𝑖,以 0結尾的最長不下降子序列度爲 𝑗,以 1結尾的最長不下降子序列爲 𝑘的 01序列數有多少。
由於不方便考慮每個狀態那些轉移得到。那我們不妨考慮對於每個狀態可以轉移到那些狀態,對於 𝑓[i][𝑗][𝑘]當前的狀態來說,有兩種轉移方法第一是在後面添加個 0,那 麼轉移到的狀態是 𝑓[𝑖+1][𝑗+1][𝑘],第二種是在後面添加一個 1,,轉移到的狀態是 𝑓[𝑖+1][𝑗][𝑚𝑎𝑥(𝑗,𝑘)+1]。
我們再考慮對答案的貢獻, 𝑓[𝑛][𝑗][𝑘]對答案的貢獻是 𝑚𝑎𝑥(𝑗,𝑘)∗𝑓[𝑛][𝑗][𝑘]。
#include<iostream>
using namespace std;
int n;
long long f[205][205][205];
#define MOD 1000000007
int main()
{
cin>>n;
f[1][1][0]=1;
f[1][0][1]=1;
long long ans=0;
for (int i=1;i<=n;i++)
{
for (int j=0;j<=i;j++)
{
for (int k=0;k<=i;k++)
{
f[i+1][j+1][k]+=f[i][j][k];
f[i+1][j][max(j,k)+1]+=f[i][j][k];
f[i+1][j+1][k]%=MOD;
f[i+1][j][max(j,k)+1]%=MOD;
}
}
}
for (int j=0;j<=n;j++)
for (int k=0;k<=n;k++)
{
ans=(ans+(long long)max(j,k)*f[n][j][k])%MOD;
}
cout<<ans;
}
:
每次往01串前加個1或者0
找規律
可得
#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define int long long
const int bs=220;
int g[210][230],f[220],n;
int p2(int k){
if(k==0) return 1;
int t=p2(k/2);
return (t*t%mod*((k&1)?2:1))%mod;
}
signed main(){
cin>>n;
f[1]=2;
g[1][0+bs]=g[1][1+bs]=1;
for(int i=2;i<=n;i++){
f[i]=(2*f[i-1]%mod+p2(i-1)+g[i-1][1+bs])%mod;
g[i][1+bs]=(g[i-1][1+bs]+g[i-1][bs])%mod;
for(int j=0;j>=1-i;j--)
g[i][j+bs]=(g[i-1][j+1+bs]+g[i-1][j-1+bs])%mod;
}
cout<<f[n]<<endl;
}